@kubb/middleware-barrel 5.0.0-alpha.65 → 5.0.0-alpha.67
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/dist/index.cjs +66 -109
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +66 -109
- package/dist/index.js.map +1 -1
- package/package.json +4 -4
- package/src/middleware.ts +11 -12
- package/src/utils/excludedPaths.ts +8 -9
- package/src/utils/getBarrelFiles.ts +16 -38
- package/src/utils/generatePerPluginBarrel.ts +0 -38
- package/src/utils/generateRootBarrel.ts +0 -33
- package/src/utils/resolveBarrelType.ts +0 -20
package/dist/index.cjs
CHANGED
|
@@ -1,13 +1,26 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
//#endregion
|
|
3
|
-
let _kubb_core = require("@kubb/core");
|
|
4
3
|
let node_path = require("node:path");
|
|
4
|
+
let _kubb_core = require("@kubb/core");
|
|
5
5
|
let _kubb_ast = require("@kubb/ast");
|
|
6
|
-
//#region src/
|
|
6
|
+
//#region ../../internals/utils/src/path.ts
|
|
7
7
|
/**
|
|
8
|
-
*
|
|
8
|
+
* Converts a filesystem path to use POSIX (`/`) separators.
|
|
9
|
+
*
|
|
10
|
+
* Most of the codebase compares and composes paths as strings (prefix matching, joining for
|
|
11
|
+
* import specifiers, splitting on `/`). On POSIX `path.resolve` already returns `/`-separated
|
|
12
|
+
* paths, but on Windows it returns `\`-separated paths, which breaks every such comparison.
|
|
13
|
+
*
|
|
14
|
+
* Routing every path that crosses a module boundary through `toPosixPath` keeps the rest of the
|
|
15
|
+
* code platform-agnostic. The conversion runs unconditionally so Windows-specific behavior is
|
|
16
|
+
* exercisable from POSIX CI.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* toPosixPath('C:\\repo\\src\\pet.ts') // 'C:/repo/src/pet.ts'
|
|
9
20
|
*/
|
|
10
|
-
|
|
21
|
+
function toPosixPath(filePath) {
|
|
22
|
+
return filePath.replaceAll("\\", "/");
|
|
23
|
+
}
|
|
11
24
|
//#endregion
|
|
12
25
|
//#region ../../internals/utils/src/buildTree.ts
|
|
13
26
|
/**
|
|
@@ -15,7 +28,9 @@ const BARREL_FILENAME = "index.ts";
|
|
|
15
28
|
* Paths outside `rootPath` are silently ignored. Children are sorted alphabetically
|
|
16
29
|
* by path so consumers (barrel exports, propagated indexes) emit a deterministic order.
|
|
17
30
|
*
|
|
18
|
-
* Both POSIX (`/`) and Windows (`\`) separators are accepted in input paths
|
|
31
|
+
* Both POSIX (`/`) and Windows (`\`) separators are accepted in input paths; emitted node
|
|
32
|
+
* paths are always POSIX-normalized so downstream prefix/lookup operations behave the same
|
|
33
|
+
* across platforms.
|
|
19
34
|
*
|
|
20
35
|
* @example
|
|
21
36
|
* ```ts
|
|
@@ -26,16 +41,17 @@ const BARREL_FILENAME = "index.ts";
|
|
|
26
41
|
* ```
|
|
27
42
|
*/
|
|
28
43
|
function buildTree(rootPath, filePaths) {
|
|
44
|
+
const normalizedRoot = toPosixPath(rootPath);
|
|
29
45
|
const root = {
|
|
30
|
-
path:
|
|
46
|
+
path: normalizedRoot,
|
|
31
47
|
children: [],
|
|
32
48
|
isFile: false
|
|
33
49
|
};
|
|
34
50
|
const childIndex = /* @__PURE__ */ new Map();
|
|
35
51
|
childIndex.set(root, /* @__PURE__ */ new Map());
|
|
36
|
-
const rootPrefix = `${
|
|
52
|
+
const rootPrefix = `${normalizedRoot}/`;
|
|
37
53
|
for (const filePath of filePaths) {
|
|
38
|
-
const normalized = filePath
|
|
54
|
+
const normalized = toPosixPath(filePath);
|
|
39
55
|
if (!normalized.startsWith(rootPrefix)) continue;
|
|
40
56
|
const parts = normalized.slice(rootPrefix.length).split("/");
|
|
41
57
|
if (parts.length === 0) continue;
|
|
@@ -71,6 +87,31 @@ function compareByPath(a, b) {
|
|
|
71
87
|
return a.path < b.path ? -1 : a.path > b.path ? 1 : 0;
|
|
72
88
|
}
|
|
73
89
|
//#endregion
|
|
90
|
+
//#region src/utils/excludedPaths.ts
|
|
91
|
+
/**
|
|
92
|
+
* Builds a POSIX-normalized prefix for a plugin's output directory, with a trailing `/`.
|
|
93
|
+
*
|
|
94
|
+
* Used to detect (and later exclude) files generated by plugins that opted out of the root barrel.
|
|
95
|
+
*/
|
|
96
|
+
function getPluginOutputPrefix(plugin, config) {
|
|
97
|
+
return `${toPosixPath((0, node_path.resolve)(config.root, config.output.path, plugin.options.output.path))}/`;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Returns `true` when `filePath` lives under any of the given excluded directory prefixes.
|
|
101
|
+
*
|
|
102
|
+
* Both sides are POSIX-normalized so Windows backslash paths match correctly.
|
|
103
|
+
*/
|
|
104
|
+
function isExcludedPath(filePath, prefixes) {
|
|
105
|
+
const normalized = toPosixPath(filePath);
|
|
106
|
+
return prefixes.values().some((prefix) => normalized.startsWith(prefix));
|
|
107
|
+
}
|
|
108
|
+
//#endregion
|
|
109
|
+
//#region src/constants.ts
|
|
110
|
+
/**
|
|
111
|
+
* Full file name for barrel files (with extension).
|
|
112
|
+
*/
|
|
113
|
+
const BARREL_FILENAME = "index.ts";
|
|
114
|
+
//#endregion
|
|
74
115
|
//#region src/utils/getBarrelFiles.ts
|
|
75
116
|
const SOURCE_EXTENSIONS = new Set([
|
|
76
117
|
".ts",
|
|
@@ -79,16 +120,6 @@ const SOURCE_EXTENSIONS = new Set([
|
|
|
79
120
|
".jsx"
|
|
80
121
|
]);
|
|
81
122
|
const BARREL_SUFFIX = `/${BARREL_FILENAME}`;
|
|
82
|
-
/**
|
|
83
|
-
* Derives a relative module specifier from `filePath` relative to `fromDir`.
|
|
84
|
-
* The source extension is preserved so `@kubb/parser-ts` can apply its `extNames` mapping.
|
|
85
|
-
*
|
|
86
|
-
* @example
|
|
87
|
-
* ```ts
|
|
88
|
-
* toRelativeModulePath('/src/gen/types', '/src/gen/types/pet.ts') // './pet.ts'
|
|
89
|
-
* toRelativeModulePath('/src/gen/types', '/src/gen/types/tags/tag.ts') // './tags/tag.ts'
|
|
90
|
-
* ```
|
|
91
|
-
*/
|
|
92
123
|
function toRelativeModulePath(fromDir, filePath) {
|
|
93
124
|
return `./${filePath.slice(fromDir.length + 1)}`;
|
|
94
125
|
}
|
|
@@ -145,8 +176,7 @@ const namedStrategy = ({ dirPath, leafPath, sourceFile }) => {
|
|
|
145
176
|
};
|
|
146
177
|
const LEAF_STRATEGIES = new Map([["all", allStrategy], ["named", namedStrategy]]);
|
|
147
178
|
/**
|
|
148
|
-
*
|
|
149
|
-
* returns its leaf paths so parents don't have to re-walk the subtree.
|
|
179
|
+
* Post-order walk that emits a barrel per visited directory.
|
|
150
180
|
*/
|
|
151
181
|
function walkAllOrNamed(node, params, isRoot, out) {
|
|
152
182
|
const subtreeLeaves = [];
|
|
@@ -168,8 +198,7 @@ function walkAllOrNamed(node, params, isRoot, out) {
|
|
|
168
198
|
return subtreeLeaves;
|
|
169
199
|
}
|
|
170
200
|
/**
|
|
171
|
-
*
|
|
172
|
-
* sub-directory is re-exported via its own barrel (recursive by design).
|
|
201
|
+
* Recursive walk that emits one barrel per directory, re-exporting files and sub-barrels.
|
|
173
202
|
*/
|
|
174
203
|
function walkPropagate(node, out) {
|
|
175
204
|
const exports = [];
|
|
@@ -185,16 +214,16 @@ function walkPropagate(node, out) {
|
|
|
185
214
|
if (exports.length > 0) out.push(makeBarrel(node.path, exports));
|
|
186
215
|
}
|
|
187
216
|
function indexRelevantFiles(files, outputPath) {
|
|
188
|
-
const outputPrefix = `${outputPath
|
|
217
|
+
const outputPrefix = `${toPosixPath(outputPath)}/`;
|
|
189
218
|
const sourceFiles = /* @__PURE__ */ new Map();
|
|
190
219
|
const paths = [];
|
|
191
220
|
for (const file of files) {
|
|
192
|
-
const normalized = file.path
|
|
221
|
+
const normalized = toPosixPath(file.path);
|
|
193
222
|
if (!normalized.startsWith(outputPrefix)) continue;
|
|
194
223
|
if (isBarrelPath(normalized)) continue;
|
|
195
224
|
if (!SOURCE_EXTENSIONS.has((0, node_path.extname)(normalized))) continue;
|
|
196
|
-
sourceFiles.set(
|
|
197
|
-
paths.push(
|
|
225
|
+
sourceFiles.set(normalized, file);
|
|
226
|
+
paths.push(normalized);
|
|
198
227
|
}
|
|
199
228
|
return {
|
|
200
229
|
sourceFiles,
|
|
@@ -203,9 +232,6 @@ function indexRelevantFiles(files, outputPath) {
|
|
|
203
232
|
}
|
|
204
233
|
/**
|
|
205
234
|
* Generates barrel `FileNode`s for the directory rooted at `outputPath`.
|
|
206
|
-
*
|
|
207
|
-
* Files outside `outputPath`, existing barrel files, and non-source extensions are filtered out
|
|
208
|
-
* before the tree is built.
|
|
209
235
|
*/
|
|
210
236
|
function getBarrelFiles({ outputPath, files, barrelType, recursive = false }) {
|
|
211
237
|
const { sourceFiles, paths } = indexRelevantFiles(files, outputPath);
|
|
@@ -226,76 +252,6 @@ function getBarrelFiles({ outputPath, files, barrelType, recursive = false }) {
|
|
|
226
252
|
return result;
|
|
227
253
|
}
|
|
228
254
|
//#endregion
|
|
229
|
-
//#region src/utils/generatePerPluginBarrel.ts
|
|
230
|
-
/**
|
|
231
|
-
* Generates barrel files for a single plugin's output directory.
|
|
232
|
-
*
|
|
233
|
-
* The barrel is placed at `<config.root>/<config.output.path>/<plugin.options.output.path>/index.ts`.
|
|
234
|
-
* When the plugin uses `group`, additional sub-directory barrels are generated so that grouped
|
|
235
|
-
* output (e.g. `petController/index.ts`) gets its own re-export entry point.
|
|
236
|
-
*/
|
|
237
|
-
function generatePerPluginBarrel({ barrelType, plugin, files, config }) {
|
|
238
|
-
return getBarrelFiles({
|
|
239
|
-
outputPath: (0, node_path.resolve)(config.root, config.output.path, plugin.options.output.path),
|
|
240
|
-
files,
|
|
241
|
-
barrelType,
|
|
242
|
-
recursive: true
|
|
243
|
-
});
|
|
244
|
-
}
|
|
245
|
-
//#endregion
|
|
246
|
-
//#region src/utils/generateRootBarrel.ts
|
|
247
|
-
/**
|
|
248
|
-
* Generates the root barrel file at `<config.root>/<config.output.path>/index.ts`.
|
|
249
|
-
*
|
|
250
|
-
* Unlike `generatePerPluginBarrel`, this does not recurse into sub-directories — each
|
|
251
|
-
* plugin is responsible for its own per-plugin barrels.
|
|
252
|
-
*/
|
|
253
|
-
function generateRootBarrel({ barrelType, files, config }) {
|
|
254
|
-
return getBarrelFiles({
|
|
255
|
-
outputPath: (0, node_path.resolve)(config.root, config.output.path),
|
|
256
|
-
files,
|
|
257
|
-
barrelType
|
|
258
|
-
});
|
|
259
|
-
}
|
|
260
|
-
//#endregion
|
|
261
|
-
//#region src/utils/excludedPaths.ts
|
|
262
|
-
/**
|
|
263
|
-
* Returns the absolute output directory of `plugin` with a trailing separator,
|
|
264
|
-
* suitable for prefix-based exclusion checks via {@link isExcludedPath}.
|
|
265
|
-
*
|
|
266
|
-
* The trailing `/` ensures `startsWith` does not match unrelated siblings
|
|
267
|
-
* (e.g. `/foo/bar` vs `/foo/barbaz/x.ts`).
|
|
268
|
-
*/
|
|
269
|
-
function getPluginOutputPrefix(plugin, config) {
|
|
270
|
-
return `${(0, node_path.resolve)(config.root, config.output.path, plugin.options.output.path)}/`;
|
|
271
|
-
}
|
|
272
|
-
/**
|
|
273
|
-
* Returns `true` when `filePath` lies under any of the directory prefixes in `prefixes`.
|
|
274
|
-
* Prefixes must already include a trailing separator (see {@link getPluginOutputPrefix}).
|
|
275
|
-
*
|
|
276
|
-
* Uses Node 22 iterator helpers (`Iterator.prototype.some`) to avoid materializing the set.
|
|
277
|
-
*/
|
|
278
|
-
function isExcludedPath(filePath, prefixes) {
|
|
279
|
-
return prefixes.values().some((prefix) => filePath.startsWith(prefix));
|
|
280
|
-
}
|
|
281
|
-
//#endregion
|
|
282
|
-
//#region src/utils/resolveBarrelType.ts
|
|
283
|
-
const DEFAULT_BARREL_TYPE = "named";
|
|
284
|
-
/**
|
|
285
|
-
* Resolves the effective barrel style for a single plugin: explicit plugin option →
|
|
286
|
-
* root config option → `'named'` default. Returns `false` when barrel generation is disabled.
|
|
287
|
-
*/
|
|
288
|
-
function resolvePluginBarrelType(plugin, config) {
|
|
289
|
-
return plugin.options.output?.barrelType ?? config.output.barrelType ?? DEFAULT_BARREL_TYPE;
|
|
290
|
-
}
|
|
291
|
-
/**
|
|
292
|
-
* Resolves the effective barrel style for the root `index.ts`: root config option → `'named'` default.
|
|
293
|
-
* Returns `false` when the root barrel is disabled.
|
|
294
|
-
*/
|
|
295
|
-
function resolveRootBarrelType(config) {
|
|
296
|
-
return config.output.barrelType ?? DEFAULT_BARREL_TYPE;
|
|
297
|
-
}
|
|
298
|
-
//#endregion
|
|
299
255
|
//#region src/middleware.ts
|
|
300
256
|
/**
|
|
301
257
|
* Generates `index.ts` barrel files for each plugin's output directory and one root barrel
|
|
@@ -330,26 +286,27 @@ const middlewareBarrel = (0, _kubb_core.defineMiddleware)({
|
|
|
330
286
|
});
|
|
331
287
|
hooks.on("kubb:plugin:end", ({ plugin }) => {
|
|
332
288
|
if (!ctx) return;
|
|
333
|
-
const barrelType =
|
|
289
|
+
const barrelType = plugin.options.output?.barrelType ?? ctx.config.output.barrelType ?? "named";
|
|
334
290
|
if (!barrelType) {
|
|
335
291
|
excludedPrefixes.add(getPluginOutputPrefix(plugin, ctx.config));
|
|
336
292
|
return;
|
|
337
293
|
}
|
|
338
|
-
const barrelFiles =
|
|
339
|
-
|
|
340
|
-
plugin,
|
|
294
|
+
const barrelFiles = getBarrelFiles({
|
|
295
|
+
outputPath: (0, node_path.resolve)(ctx.config.root, ctx.config.output.path, plugin.options.output.path),
|
|
341
296
|
files: ctx.files,
|
|
342
|
-
|
|
297
|
+
barrelType,
|
|
298
|
+
recursive: true
|
|
343
299
|
});
|
|
344
300
|
if (barrelFiles.length > 0) ctx.upsertFile(...barrelFiles);
|
|
345
301
|
});
|
|
346
302
|
hooks.on("kubb:plugins:end", ({ files, config, upsertFile }) => {
|
|
347
|
-
const rootBarrelType =
|
|
303
|
+
const rootBarrelType = config.output.barrelType ?? "named";
|
|
348
304
|
if (!rootBarrelType) return;
|
|
349
|
-
const
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
305
|
+
const filteredFiles = excludedPrefixes.size === 0 ? files : files.filter((f) => !isExcludedPath(f.path, excludedPrefixes));
|
|
306
|
+
const rootBarrelFiles = getBarrelFiles({
|
|
307
|
+
outputPath: (0, node_path.resolve)(config.root, config.output.path),
|
|
308
|
+
files: filteredFiles,
|
|
309
|
+
barrelType: rootBarrelType
|
|
353
310
|
});
|
|
354
311
|
if (rootBarrelFiles.length > 0) upsertFile(...rootBarrelFiles);
|
|
355
312
|
});
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":[],"sources":["../src/constants.ts","../../../internals/utils/src/buildTree.ts","../src/utils/getBarrelFiles.ts","../src/utils/generatePerPluginBarrel.ts","../src/utils/generateRootBarrel.ts","../src/utils/excludedPaths.ts","../src/utils/resolveBarrelType.ts","../src/middleware.ts"],"sourcesContent":["/**\n * Full file name for barrel files (with extension).\n */\nexport const BARREL_FILENAME = 'index.ts' as const\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.\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.\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 root: BuildTree = { path: rootPath, 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 normalizedRoot = rootPath.replaceAll('\\\\', '/')\n const rootPrefix = `${normalizedRoot}/`\n\n for (const filePath of filePaths) {\n const normalized = filePath.replaceAll('\\\\', '/')\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 } 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 } from '@internals/utils'\n\nconst SOURCE_EXTENSIONS = new Set(['.ts', '.tsx', '.js', '.jsx'])\nconst BARREL_SUFFIX = `/${BARREL_FILENAME}`\n\n/**\n * Derives a relative module specifier from `filePath` relative to `fromDir`.\n * The source extension is preserved so `@kubb/parser-ts` can apply its `extNames` mapping.\n *\n * @example\n * ```ts\n * toRelativeModulePath('/src/gen/types', '/src/gen/types/pet.ts') // './pet.ts'\n * toRelativeModulePath('/src/gen/types', '/src/gen/types/tags/tag.ts') // './tags/tag.ts'\n * ```\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 })\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<Exclude<BarrelType, 'propagate'>, 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 * Single-pass post-order traversal that emits a barrel for each visited directory and\n * returns its leaf paths so parents don't have to re-walk the subtree.\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 // Sub-directory barrels are only emitted when the caller asked for them.\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 * Emits one barrel per directory: every direct child file is re-exported and every\n * sub-directory is re-exported via its own barrel (recursive by design).\n */\nfunction walkPropagate(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 walkPropagate(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 /**\n * `path → FileNode` lookup limited to files that participate in barrel generation.\n */\n sourceFiles: ReadonlyMap<string, FileNode>\n /**\n * Original (un-normalized) paths of `sourceFiles`, in input order — used as input for {@link buildTree}.\n */\n paths: ReadonlyArray<string>\n}\n\nfunction indexRelevantFiles(files: ReadonlyArray<FileNode>, outputPath: string): IndexedFiles {\n const outputPrefix = `${outputPath.replaceAll('\\\\', '/')}/`\n const sourceFiles = new Map<string, FileNode>()\n const paths: Array<string> = []\n\n for (const file of files) {\n const normalized = file.path.replaceAll('\\\\', '/')\n if (!normalized.startsWith(outputPrefix)) continue\n if (isBarrelPath(normalized)) continue\n if (!SOURCE_EXTENSIONS.has(extname(normalized))) continue\n\n sourceFiles.set(file.path, file)\n paths.push(file.path)\n }\n\n return { sourceFiles, paths }\n}\n\nexport type GetBarrelFilesParams = {\n /**\n * Absolute path to the directory the barrel(s) should be rooted at.\n * Files outside this directory are ignored.\n */\n outputPath: string\n /**\n * Full set of generated files across all plugins.\n * Used both to discover what to re-export and to read each file's indexable sources.\n */\n files: ReadonlyArray<FileNode>\n /**\n * Re-export style used in the generated barrel(s).\n */\n barrelType: BarrelType\n /**\n * When `true`, also generate a barrel for each sub-directory of `outputPath`.\n * Used by per-plugin barrels so that grouped output (e.g. `petController/`) gets its own `index.ts`.\n *\n * Has no effect for `barrelType: 'propagate'`, which always recurses by design.\n *\n * @default false\n */\n recursive?: boolean\n}\n\n/**\n * Generates barrel `FileNode`s for the directory rooted at `outputPath`.\n *\n * Files outside `outputPath`, existing barrel files, and non-source extensions are filtered out\n * before the tree is built.\n */\nexport function getBarrelFiles({ outputPath, files, barrelType, 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 if (barrelType === 'propagate') {\n walkPropagate(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 { resolve } from 'node:path'\nimport type { FileNode } from '@kubb/ast'\nimport type { Config, NormalizedPlugin } from '@kubb/core'\nimport type { BarrelType } from '../types.ts'\nimport { getBarrelFiles } from './getBarrelFiles.ts'\n\nexport type GeneratePerPluginBarrelParams = {\n /**\n * Re-export style used in the plugin's barrel file(s).\n */\n barrelType: BarrelType\n /**\n * Plugin whose `output.path` determines the barrel directory.\n */\n plugin: NormalizedPlugin\n /**\n * Full set of generated files across all plugins.\n * Files outside the plugin's output directory are filtered out automatically.\n */\n files: ReadonlyArray<FileNode>\n /**\n * Resolved Kubb config; used to compute the absolute output directory.\n */\n config: Config\n}\n\n/**\n * Generates barrel files for a single plugin's output directory.\n *\n * The barrel is placed at `<config.root>/<config.output.path>/<plugin.options.output.path>/index.ts`.\n * When the plugin uses `group`, additional sub-directory barrels are generated so that grouped\n * output (e.g. `petController/index.ts`) gets its own re-export entry point.\n */\nexport function generatePerPluginBarrel({ barrelType, plugin, files, config }: GeneratePerPluginBarrelParams): Array<FileNode> {\n const outputPath = resolve(config.root, config.output.path, plugin.options.output.path)\n\n return getBarrelFiles({ outputPath, files, barrelType, recursive: true })\n}\n","import { resolve } from 'node:path'\nimport type { FileNode } from '@kubb/ast'\nimport type { Config } from '@kubb/core'\nimport type { BarrelType } from '../types.ts'\nimport { getBarrelFiles } from './getBarrelFiles.ts'\n\nexport type GenerateRootBarrelParams = {\n /**\n * Re-export style used in the root barrel file.\n */\n barrelType: BarrelType\n /**\n * Files eligible for re-export. The middleware filters out files belonging to plugins\n * with `barrelType: false` before passing them in.\n */\n files: ReadonlyArray<FileNode>\n /**\n * Resolved Kubb config; used to compute the root output directory.\n */\n config: Config\n}\n\n/**\n * Generates the root barrel file at `<config.root>/<config.output.path>/index.ts`.\n *\n * Unlike `generatePerPluginBarrel`, this does not recurse into sub-directories — each\n * plugin is responsible for its own per-plugin barrels.\n */\nexport function generateRootBarrel({ barrelType, files, config }: GenerateRootBarrelParams): Array<FileNode> {\n const outputPath = resolve(config.root, config.output.path)\n\n return getBarrelFiles({ outputPath, files, barrelType })\n}\n","import { resolve } from 'node:path'\nimport type { Config, NormalizedPlugin } from '@kubb/core'\n\n/**\n * Returns the absolute output directory of `plugin` with a trailing separator,\n * suitable for prefix-based exclusion checks via {@link isExcludedPath}.\n *\n * The trailing `/` ensures `startsWith` does not match unrelated siblings\n * (e.g. `/foo/bar` vs `/foo/barbaz/x.ts`).\n */\nexport function getPluginOutputPrefix(plugin: NormalizedPlugin, config: Config): string {\n return `${resolve(config.root, config.output.path, plugin.options.output.path)}/`\n}\n\n/**\n * Returns `true` when `filePath` lies under any of the directory prefixes in `prefixes`.\n * Prefixes must already include a trailing separator (see {@link getPluginOutputPrefix}).\n *\n * Uses Node 22 iterator helpers (`Iterator.prototype.some`) to avoid materializing the set.\n */\nexport function isExcludedPath(filePath: string, prefixes: ReadonlySet<string>): boolean {\n return prefixes.values().some((prefix) => filePath.startsWith(prefix))\n}\n","import type { Config, NormalizedPlugin } from '@kubb/core'\nimport type { BarrelType } from '../types.ts'\n\nconst DEFAULT_BARREL_TYPE: BarrelType = 'named'\n\n/**\n * Resolves the effective barrel style for a single plugin: explicit plugin option →\n * root config option → `'named'` default. Returns `false` when barrel generation is disabled.\n */\nexport function resolvePluginBarrelType(plugin: NormalizedPlugin, config: Config): BarrelType | false {\n return plugin.options.output?.barrelType ?? config.output.barrelType ?? DEFAULT_BARREL_TYPE\n}\n\n/**\n * Resolves the effective barrel style for the root `index.ts`: root config option → `'named'` default.\n * Returns `false` when the root barrel is disabled.\n */\nexport function resolveRootBarrelType(config: Config): BarrelType | false {\n return config.output.barrelType ?? DEFAULT_BARREL_TYPE\n}\n","import { defineMiddleware } from '@kubb/core'\nimport type { KubbBuildStartContext } from '@kubb/core'\nimport type { BarrelType } from './types.ts'\nimport { generatePerPluginBarrel } from './utils/generatePerPluginBarrel.ts'\nimport { generateRootBarrel } from './utils/generateRootBarrel.ts'\nimport { getPluginOutputPrefix, isExcludedPath } from './utils/excludedPaths.ts'\nimport { resolvePluginBarrelType, resolveRootBarrelType } from './utils/resolveBarrelType.ts'\n\ndeclare global {\n namespace Kubb {\n interface PluginOptionsRegistry {\n output: {\n /**\n * Re-export style for this plugin's barrel file.\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.barrelType` when omitted.\n *\n * @default 'named'\n */\n barrelType?: BarrelType | false\n }\n }\n interface ConfigOptionsRegistry {\n output: {\n /**\n * Re-export style 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.barrelType`.\n *\n * @default 'named'\n */\n barrelType?: BarrelType | false\n }\n }\n }\n}\n\n/**\n * Generates `index.ts` barrel files for each plugin's output directory and one root barrel\n * at `config.output.path/index.ts`.\n *\n * Plugins inherit `output.barrelType` from `config.output.barrelType` (which itself defaults to `'named'`).\n * Setting `barrelType: false` on a plugin disables its barrel and excludes the plugin's files from the\n * root barrel as well.\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', barrelType: 'named' },\n * plugins: [\n * pluginTs({ output: { path: 'types', barrelType: 'all' } }),\n * pluginZod({ output: { path: 'schemas' } }),\n * ],\n * middleware: [middlewareBarrel],\n * })\n * ```\n */\nexport const middlewareBarrel = defineMiddleware({\n name: 'middleware-barrel',\n install(hooks) {\n let ctx: KubbBuildStartContext | undefined\n const excludedPrefixes = new Set<string>()\n\n hooks.on('kubb:build:start', (buildCtx) => {\n ctx = buildCtx\n })\n\n hooks.on('kubb:plugin:end', ({ plugin }) => {\n if (!ctx) return\n\n const barrelType = resolvePluginBarrelType(plugin, ctx.config)\n\n if (!barrelType) {\n excludedPrefixes.add(getPluginOutputPrefix(plugin, ctx.config))\n return\n }\n\n const barrelFiles = generatePerPluginBarrel({\n barrelType,\n plugin,\n files: ctx.files,\n config: ctx.config,\n })\n\n if (barrelFiles.length > 0) {\n ctx.upsertFile(...barrelFiles)\n }\n })\n\n hooks.on('kubb:plugins:end', ({ files, config, upsertFile }) => {\n const rootBarrelType = resolveRootBarrelType(config)\n if (!rootBarrelType) return\n\n const filteredFiles = excludedPrefixes.size === 0 ? files : files.filter((f) => !isExcludedPath(f.path, excludedPrefixes))\n\n const rootBarrelFiles = generateRootBarrel({\n barrelType: rootBarrelType,\n files: filteredFiles,\n config,\n })\n\n if (rootBarrelFiles.length > 0) {\n upsertFile(...rootBarrelFiles)\n }\n })\n },\n})\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","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 })\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<Exclude<BarrelType, 'propagate'>, 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 */\nfunction walkPropagate(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 walkPropagate(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\nexport type 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 * Re-export style 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 * - `'propagate'` emits one barrel per directory and chains sub-barrels\n */\n barrelType: BarrelType\n /**\n * Also generate a barrel for each sub-directory of `outputPath`.\n * No effect for `barrelType: 'propagate'`, which always recurses.\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, 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 if (barrelType === 'propagate') {\n walkPropagate(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 { resolve } from 'node:path'\nimport { defineMiddleware } from '@kubb/core'\nimport type { KubbBuildStartContext } from '@kubb/core'\nimport type { BarrelType } 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 * Re-export style for this plugin's barrel file.\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.barrelType` when omitted.\n *\n * @default 'named'\n */\n barrelType?: BarrelType | false\n }\n }\n interface ConfigOptionsRegistry {\n output: {\n /**\n * Re-export style 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.barrelType`.\n *\n * @default 'named'\n */\n barrelType?: BarrelType | false\n }\n }\n }\n}\n\n/**\n * Generates `index.ts` barrel files for each plugin's output directory and one root barrel\n * at `config.output.path/index.ts`.\n *\n * Plugins inherit `output.barrelType` from `config.output.barrelType` (which itself defaults to `'named'`).\n * Setting `barrelType: false` on a plugin disables its barrel and excludes the plugin's files from the\n * root barrel as well.\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', barrelType: 'named' },\n * plugins: [\n * pluginTs({ output: { path: 'types', barrelType: 'all' } }),\n * pluginZod({ output: { path: 'schemas' } }),\n * ],\n * middleware: [middlewareBarrel],\n * })\n * ```\n */\nexport const middlewareBarrel = defineMiddleware({\n name: 'middleware-barrel',\n install(hooks) {\n let ctx: KubbBuildStartContext | undefined\n const excludedPrefixes = new Set<string>()\n\n hooks.on('kubb:build:start', (buildCtx) => {\n ctx = buildCtx\n })\n\n hooks.on('kubb:plugin:end', ({ plugin }) => {\n if (!ctx) return\n\n const barrelType = plugin.options.output?.barrelType ?? ctx.config.output.barrelType ?? 'named'\n\n if (!barrelType) {\n excludedPrefixes.add(getPluginOutputPrefix(plugin, ctx.config))\n return\n }\n\n const barrelFiles = getBarrelFiles({\n outputPath: resolve(ctx.config.root, ctx.config.output.path, plugin.options.output.path),\n files: ctx.files,\n barrelType,\n recursive: true,\n })\n\n if (barrelFiles.length > 0) {\n ctx.upsertFile(...barrelFiles)\n }\n })\n\n hooks.on('kubb:plugins:end', ({ files, config, upsertFile }) => {\n const rootBarrelType = config.output.barrelType ?? 'named'\n if (!rootBarrelType) return\n\n const filteredFiles = excludedPrefixes.size === 0 ? files : files.filter((f) => !isExcludedPath(f.path, excludedPrefixes))\n\n const rootBarrelFiles = getBarrelFiles({\n outputPath: resolve(config.root, config.output.path),\n files: filteredFiles,\n barrelType: rootBarrelType,\n })\n\n if (rootBarrelFiles.length > 0) {\n upsertFile(...rootBarrelFiles)\n }\n })\n },\n})\n"],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -1,12 +1,25 @@
|
|
|
1
1
|
import "./chunk--u3MIqq1.js";
|
|
2
|
-
import { defineMiddleware } from "@kubb/core";
|
|
3
2
|
import { extname, resolve } from "node:path";
|
|
3
|
+
import { defineMiddleware } from "@kubb/core";
|
|
4
4
|
import { createExport, createFile } from "@kubb/ast";
|
|
5
|
-
//#region src/
|
|
5
|
+
//#region ../../internals/utils/src/path.ts
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
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'
|
|
8
19
|
*/
|
|
9
|
-
|
|
20
|
+
function toPosixPath(filePath) {
|
|
21
|
+
return filePath.replaceAll("\\", "/");
|
|
22
|
+
}
|
|
10
23
|
//#endregion
|
|
11
24
|
//#region ../../internals/utils/src/buildTree.ts
|
|
12
25
|
/**
|
|
@@ -14,7 +27,9 @@ const BARREL_FILENAME = "index.ts";
|
|
|
14
27
|
* Paths outside `rootPath` are silently ignored. Children are sorted alphabetically
|
|
15
28
|
* by path so consumers (barrel exports, propagated indexes) emit a deterministic order.
|
|
16
29
|
*
|
|
17
|
-
* Both POSIX (`/`) and Windows (`\`) separators are accepted in input paths
|
|
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.
|
|
18
33
|
*
|
|
19
34
|
* @example
|
|
20
35
|
* ```ts
|
|
@@ -25,16 +40,17 @@ const BARREL_FILENAME = "index.ts";
|
|
|
25
40
|
* ```
|
|
26
41
|
*/
|
|
27
42
|
function buildTree(rootPath, filePaths) {
|
|
43
|
+
const normalizedRoot = toPosixPath(rootPath);
|
|
28
44
|
const root = {
|
|
29
|
-
path:
|
|
45
|
+
path: normalizedRoot,
|
|
30
46
|
children: [],
|
|
31
47
|
isFile: false
|
|
32
48
|
};
|
|
33
49
|
const childIndex = /* @__PURE__ */ new Map();
|
|
34
50
|
childIndex.set(root, /* @__PURE__ */ new Map());
|
|
35
|
-
const rootPrefix = `${
|
|
51
|
+
const rootPrefix = `${normalizedRoot}/`;
|
|
36
52
|
for (const filePath of filePaths) {
|
|
37
|
-
const normalized = filePath
|
|
53
|
+
const normalized = toPosixPath(filePath);
|
|
38
54
|
if (!normalized.startsWith(rootPrefix)) continue;
|
|
39
55
|
const parts = normalized.slice(rootPrefix.length).split("/");
|
|
40
56
|
if (parts.length === 0) continue;
|
|
@@ -70,6 +86,31 @@ function compareByPath(a, b) {
|
|
|
70
86
|
return a.path < b.path ? -1 : a.path > b.path ? 1 : 0;
|
|
71
87
|
}
|
|
72
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
|
+
//#region src/constants.ts
|
|
109
|
+
/**
|
|
110
|
+
* Full file name for barrel files (with extension).
|
|
111
|
+
*/
|
|
112
|
+
const BARREL_FILENAME = "index.ts";
|
|
113
|
+
//#endregion
|
|
73
114
|
//#region src/utils/getBarrelFiles.ts
|
|
74
115
|
const SOURCE_EXTENSIONS = new Set([
|
|
75
116
|
".ts",
|
|
@@ -78,16 +119,6 @@ const SOURCE_EXTENSIONS = new Set([
|
|
|
78
119
|
".jsx"
|
|
79
120
|
]);
|
|
80
121
|
const BARREL_SUFFIX = `/${BARREL_FILENAME}`;
|
|
81
|
-
/**
|
|
82
|
-
* Derives a relative module specifier from `filePath` relative to `fromDir`.
|
|
83
|
-
* The source extension is preserved so `@kubb/parser-ts` can apply its `extNames` mapping.
|
|
84
|
-
*
|
|
85
|
-
* @example
|
|
86
|
-
* ```ts
|
|
87
|
-
* toRelativeModulePath('/src/gen/types', '/src/gen/types/pet.ts') // './pet.ts'
|
|
88
|
-
* toRelativeModulePath('/src/gen/types', '/src/gen/types/tags/tag.ts') // './tags/tag.ts'
|
|
89
|
-
* ```
|
|
90
|
-
*/
|
|
91
122
|
function toRelativeModulePath(fromDir, filePath) {
|
|
92
123
|
return `./${filePath.slice(fromDir.length + 1)}`;
|
|
93
124
|
}
|
|
@@ -144,8 +175,7 @@ const namedStrategy = ({ dirPath, leafPath, sourceFile }) => {
|
|
|
144
175
|
};
|
|
145
176
|
const LEAF_STRATEGIES = new Map([["all", allStrategy], ["named", namedStrategy]]);
|
|
146
177
|
/**
|
|
147
|
-
*
|
|
148
|
-
* returns its leaf paths so parents don't have to re-walk the subtree.
|
|
178
|
+
* Post-order walk that emits a barrel per visited directory.
|
|
149
179
|
*/
|
|
150
180
|
function walkAllOrNamed(node, params, isRoot, out) {
|
|
151
181
|
const subtreeLeaves = [];
|
|
@@ -167,8 +197,7 @@ function walkAllOrNamed(node, params, isRoot, out) {
|
|
|
167
197
|
return subtreeLeaves;
|
|
168
198
|
}
|
|
169
199
|
/**
|
|
170
|
-
*
|
|
171
|
-
* sub-directory is re-exported via its own barrel (recursive by design).
|
|
200
|
+
* Recursive walk that emits one barrel per directory, re-exporting files and sub-barrels.
|
|
172
201
|
*/
|
|
173
202
|
function walkPropagate(node, out) {
|
|
174
203
|
const exports = [];
|
|
@@ -184,16 +213,16 @@ function walkPropagate(node, out) {
|
|
|
184
213
|
if (exports.length > 0) out.push(makeBarrel(node.path, exports));
|
|
185
214
|
}
|
|
186
215
|
function indexRelevantFiles(files, outputPath) {
|
|
187
|
-
const outputPrefix = `${outputPath
|
|
216
|
+
const outputPrefix = `${toPosixPath(outputPath)}/`;
|
|
188
217
|
const sourceFiles = /* @__PURE__ */ new Map();
|
|
189
218
|
const paths = [];
|
|
190
219
|
for (const file of files) {
|
|
191
|
-
const normalized = file.path
|
|
220
|
+
const normalized = toPosixPath(file.path);
|
|
192
221
|
if (!normalized.startsWith(outputPrefix)) continue;
|
|
193
222
|
if (isBarrelPath(normalized)) continue;
|
|
194
223
|
if (!SOURCE_EXTENSIONS.has(extname(normalized))) continue;
|
|
195
|
-
sourceFiles.set(
|
|
196
|
-
paths.push(
|
|
224
|
+
sourceFiles.set(normalized, file);
|
|
225
|
+
paths.push(normalized);
|
|
197
226
|
}
|
|
198
227
|
return {
|
|
199
228
|
sourceFiles,
|
|
@@ -202,9 +231,6 @@ function indexRelevantFiles(files, outputPath) {
|
|
|
202
231
|
}
|
|
203
232
|
/**
|
|
204
233
|
* Generates barrel `FileNode`s for the directory rooted at `outputPath`.
|
|
205
|
-
*
|
|
206
|
-
* Files outside `outputPath`, existing barrel files, and non-source extensions are filtered out
|
|
207
|
-
* before the tree is built.
|
|
208
234
|
*/
|
|
209
235
|
function getBarrelFiles({ outputPath, files, barrelType, recursive = false }) {
|
|
210
236
|
const { sourceFiles, paths } = indexRelevantFiles(files, outputPath);
|
|
@@ -225,76 +251,6 @@ function getBarrelFiles({ outputPath, files, barrelType, recursive = false }) {
|
|
|
225
251
|
return result;
|
|
226
252
|
}
|
|
227
253
|
//#endregion
|
|
228
|
-
//#region src/utils/generatePerPluginBarrel.ts
|
|
229
|
-
/**
|
|
230
|
-
* Generates barrel files for a single plugin's output directory.
|
|
231
|
-
*
|
|
232
|
-
* The barrel is placed at `<config.root>/<config.output.path>/<plugin.options.output.path>/index.ts`.
|
|
233
|
-
* When the plugin uses `group`, additional sub-directory barrels are generated so that grouped
|
|
234
|
-
* output (e.g. `petController/index.ts`) gets its own re-export entry point.
|
|
235
|
-
*/
|
|
236
|
-
function generatePerPluginBarrel({ barrelType, plugin, files, config }) {
|
|
237
|
-
return getBarrelFiles({
|
|
238
|
-
outputPath: resolve(config.root, config.output.path, plugin.options.output.path),
|
|
239
|
-
files,
|
|
240
|
-
barrelType,
|
|
241
|
-
recursive: true
|
|
242
|
-
});
|
|
243
|
-
}
|
|
244
|
-
//#endregion
|
|
245
|
-
//#region src/utils/generateRootBarrel.ts
|
|
246
|
-
/**
|
|
247
|
-
* Generates the root barrel file at `<config.root>/<config.output.path>/index.ts`.
|
|
248
|
-
*
|
|
249
|
-
* Unlike `generatePerPluginBarrel`, this does not recurse into sub-directories — each
|
|
250
|
-
* plugin is responsible for its own per-plugin barrels.
|
|
251
|
-
*/
|
|
252
|
-
function generateRootBarrel({ barrelType, files, config }) {
|
|
253
|
-
return getBarrelFiles({
|
|
254
|
-
outputPath: resolve(config.root, config.output.path),
|
|
255
|
-
files,
|
|
256
|
-
barrelType
|
|
257
|
-
});
|
|
258
|
-
}
|
|
259
|
-
//#endregion
|
|
260
|
-
//#region src/utils/excludedPaths.ts
|
|
261
|
-
/**
|
|
262
|
-
* Returns the absolute output directory of `plugin` with a trailing separator,
|
|
263
|
-
* suitable for prefix-based exclusion checks via {@link isExcludedPath}.
|
|
264
|
-
*
|
|
265
|
-
* The trailing `/` ensures `startsWith` does not match unrelated siblings
|
|
266
|
-
* (e.g. `/foo/bar` vs `/foo/barbaz/x.ts`).
|
|
267
|
-
*/
|
|
268
|
-
function getPluginOutputPrefix(plugin, config) {
|
|
269
|
-
return `${resolve(config.root, config.output.path, plugin.options.output.path)}/`;
|
|
270
|
-
}
|
|
271
|
-
/**
|
|
272
|
-
* Returns `true` when `filePath` lies under any of the directory prefixes in `prefixes`.
|
|
273
|
-
* Prefixes must already include a trailing separator (see {@link getPluginOutputPrefix}).
|
|
274
|
-
*
|
|
275
|
-
* Uses Node 22 iterator helpers (`Iterator.prototype.some`) to avoid materializing the set.
|
|
276
|
-
*/
|
|
277
|
-
function isExcludedPath(filePath, prefixes) {
|
|
278
|
-
return prefixes.values().some((prefix) => filePath.startsWith(prefix));
|
|
279
|
-
}
|
|
280
|
-
//#endregion
|
|
281
|
-
//#region src/utils/resolveBarrelType.ts
|
|
282
|
-
const DEFAULT_BARREL_TYPE = "named";
|
|
283
|
-
/**
|
|
284
|
-
* Resolves the effective barrel style for a single plugin: explicit plugin option →
|
|
285
|
-
* root config option → `'named'` default. Returns `false` when barrel generation is disabled.
|
|
286
|
-
*/
|
|
287
|
-
function resolvePluginBarrelType(plugin, config) {
|
|
288
|
-
return plugin.options.output?.barrelType ?? config.output.barrelType ?? DEFAULT_BARREL_TYPE;
|
|
289
|
-
}
|
|
290
|
-
/**
|
|
291
|
-
* Resolves the effective barrel style for the root `index.ts`: root config option → `'named'` default.
|
|
292
|
-
* Returns `false` when the root barrel is disabled.
|
|
293
|
-
*/
|
|
294
|
-
function resolveRootBarrelType(config) {
|
|
295
|
-
return config.output.barrelType ?? DEFAULT_BARREL_TYPE;
|
|
296
|
-
}
|
|
297
|
-
//#endregion
|
|
298
254
|
//#region src/middleware.ts
|
|
299
255
|
/**
|
|
300
256
|
* Generates `index.ts` barrel files for each plugin's output directory and one root barrel
|
|
@@ -329,26 +285,27 @@ const middlewareBarrel = defineMiddleware({
|
|
|
329
285
|
});
|
|
330
286
|
hooks.on("kubb:plugin:end", ({ plugin }) => {
|
|
331
287
|
if (!ctx) return;
|
|
332
|
-
const barrelType =
|
|
288
|
+
const barrelType = plugin.options.output?.barrelType ?? ctx.config.output.barrelType ?? "named";
|
|
333
289
|
if (!barrelType) {
|
|
334
290
|
excludedPrefixes.add(getPluginOutputPrefix(plugin, ctx.config));
|
|
335
291
|
return;
|
|
336
292
|
}
|
|
337
|
-
const barrelFiles =
|
|
338
|
-
|
|
339
|
-
plugin,
|
|
293
|
+
const barrelFiles = getBarrelFiles({
|
|
294
|
+
outputPath: resolve(ctx.config.root, ctx.config.output.path, plugin.options.output.path),
|
|
340
295
|
files: ctx.files,
|
|
341
|
-
|
|
296
|
+
barrelType,
|
|
297
|
+
recursive: true
|
|
342
298
|
});
|
|
343
299
|
if (barrelFiles.length > 0) ctx.upsertFile(...barrelFiles);
|
|
344
300
|
});
|
|
345
301
|
hooks.on("kubb:plugins:end", ({ files, config, upsertFile }) => {
|
|
346
|
-
const rootBarrelType =
|
|
302
|
+
const rootBarrelType = config.output.barrelType ?? "named";
|
|
347
303
|
if (!rootBarrelType) return;
|
|
348
|
-
const
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
304
|
+
const filteredFiles = excludedPrefixes.size === 0 ? files : files.filter((f) => !isExcludedPath(f.path, excludedPrefixes));
|
|
305
|
+
const rootBarrelFiles = getBarrelFiles({
|
|
306
|
+
outputPath: resolve(config.root, config.output.path),
|
|
307
|
+
files: filteredFiles,
|
|
308
|
+
barrelType: rootBarrelType
|
|
352
309
|
});
|
|
353
310
|
if (rootBarrelFiles.length > 0) upsertFile(...rootBarrelFiles);
|
|
354
311
|
});
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/constants.ts","../../../internals/utils/src/buildTree.ts","../src/utils/getBarrelFiles.ts","../src/utils/generatePerPluginBarrel.ts","../src/utils/generateRootBarrel.ts","../src/utils/excludedPaths.ts","../src/utils/resolveBarrelType.ts","../src/middleware.ts"],"sourcesContent":["/**\n * Full file name for barrel files (with extension).\n */\nexport const BARREL_FILENAME = 'index.ts' as const\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.\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.\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 root: BuildTree = { path: rootPath, 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 normalizedRoot = rootPath.replaceAll('\\\\', '/')\n const rootPrefix = `${normalizedRoot}/`\n\n for (const filePath of filePaths) {\n const normalized = filePath.replaceAll('\\\\', '/')\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 } 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 } from '@internals/utils'\n\nconst SOURCE_EXTENSIONS = new Set(['.ts', '.tsx', '.js', '.jsx'])\nconst BARREL_SUFFIX = `/${BARREL_FILENAME}`\n\n/**\n * Derives a relative module specifier from `filePath` relative to `fromDir`.\n * The source extension is preserved so `@kubb/parser-ts` can apply its `extNames` mapping.\n *\n * @example\n * ```ts\n * toRelativeModulePath('/src/gen/types', '/src/gen/types/pet.ts') // './pet.ts'\n * toRelativeModulePath('/src/gen/types', '/src/gen/types/tags/tag.ts') // './tags/tag.ts'\n * ```\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 })\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<Exclude<BarrelType, 'propagate'>, 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 * Single-pass post-order traversal that emits a barrel for each visited directory and\n * returns its leaf paths so parents don't have to re-walk the subtree.\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 // Sub-directory barrels are only emitted when the caller asked for them.\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 * Emits one barrel per directory: every direct child file is re-exported and every\n * sub-directory is re-exported via its own barrel (recursive by design).\n */\nfunction walkPropagate(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 walkPropagate(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 /**\n * `path → FileNode` lookup limited to files that participate in barrel generation.\n */\n sourceFiles: ReadonlyMap<string, FileNode>\n /**\n * Original (un-normalized) paths of `sourceFiles`, in input order — used as input for {@link buildTree}.\n */\n paths: ReadonlyArray<string>\n}\n\nfunction indexRelevantFiles(files: ReadonlyArray<FileNode>, outputPath: string): IndexedFiles {\n const outputPrefix = `${outputPath.replaceAll('\\\\', '/')}/`\n const sourceFiles = new Map<string, FileNode>()\n const paths: Array<string> = []\n\n for (const file of files) {\n const normalized = file.path.replaceAll('\\\\', '/')\n if (!normalized.startsWith(outputPrefix)) continue\n if (isBarrelPath(normalized)) continue\n if (!SOURCE_EXTENSIONS.has(extname(normalized))) continue\n\n sourceFiles.set(file.path, file)\n paths.push(file.path)\n }\n\n return { sourceFiles, paths }\n}\n\nexport type GetBarrelFilesParams = {\n /**\n * Absolute path to the directory the barrel(s) should be rooted at.\n * Files outside this directory are ignored.\n */\n outputPath: string\n /**\n * Full set of generated files across all plugins.\n * Used both to discover what to re-export and to read each file's indexable sources.\n */\n files: ReadonlyArray<FileNode>\n /**\n * Re-export style used in the generated barrel(s).\n */\n barrelType: BarrelType\n /**\n * When `true`, also generate a barrel for each sub-directory of `outputPath`.\n * Used by per-plugin barrels so that grouped output (e.g. `petController/`) gets its own `index.ts`.\n *\n * Has no effect for `barrelType: 'propagate'`, which always recurses by design.\n *\n * @default false\n */\n recursive?: boolean\n}\n\n/**\n * Generates barrel `FileNode`s for the directory rooted at `outputPath`.\n *\n * Files outside `outputPath`, existing barrel files, and non-source extensions are filtered out\n * before the tree is built.\n */\nexport function getBarrelFiles({ outputPath, files, barrelType, 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 if (barrelType === 'propagate') {\n walkPropagate(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 { resolve } from 'node:path'\nimport type { FileNode } from '@kubb/ast'\nimport type { Config, NormalizedPlugin } from '@kubb/core'\nimport type { BarrelType } from '../types.ts'\nimport { getBarrelFiles } from './getBarrelFiles.ts'\n\nexport type GeneratePerPluginBarrelParams = {\n /**\n * Re-export style used in the plugin's barrel file(s).\n */\n barrelType: BarrelType\n /**\n * Plugin whose `output.path` determines the barrel directory.\n */\n plugin: NormalizedPlugin\n /**\n * Full set of generated files across all plugins.\n * Files outside the plugin's output directory are filtered out automatically.\n */\n files: ReadonlyArray<FileNode>\n /**\n * Resolved Kubb config; used to compute the absolute output directory.\n */\n config: Config\n}\n\n/**\n * Generates barrel files for a single plugin's output directory.\n *\n * The barrel is placed at `<config.root>/<config.output.path>/<plugin.options.output.path>/index.ts`.\n * When the plugin uses `group`, additional sub-directory barrels are generated so that grouped\n * output (e.g. `petController/index.ts`) gets its own re-export entry point.\n */\nexport function generatePerPluginBarrel({ barrelType, plugin, files, config }: GeneratePerPluginBarrelParams): Array<FileNode> {\n const outputPath = resolve(config.root, config.output.path, plugin.options.output.path)\n\n return getBarrelFiles({ outputPath, files, barrelType, recursive: true })\n}\n","import { resolve } from 'node:path'\nimport type { FileNode } from '@kubb/ast'\nimport type { Config } from '@kubb/core'\nimport type { BarrelType } from '../types.ts'\nimport { getBarrelFiles } from './getBarrelFiles.ts'\n\nexport type GenerateRootBarrelParams = {\n /**\n * Re-export style used in the root barrel file.\n */\n barrelType: BarrelType\n /**\n * Files eligible for re-export. The middleware filters out files belonging to plugins\n * with `barrelType: false` before passing them in.\n */\n files: ReadonlyArray<FileNode>\n /**\n * Resolved Kubb config; used to compute the root output directory.\n */\n config: Config\n}\n\n/**\n * Generates the root barrel file at `<config.root>/<config.output.path>/index.ts`.\n *\n * Unlike `generatePerPluginBarrel`, this does not recurse into sub-directories — each\n * plugin is responsible for its own per-plugin barrels.\n */\nexport function generateRootBarrel({ barrelType, files, config }: GenerateRootBarrelParams): Array<FileNode> {\n const outputPath = resolve(config.root, config.output.path)\n\n return getBarrelFiles({ outputPath, files, barrelType })\n}\n","import { resolve } from 'node:path'\nimport type { Config, NormalizedPlugin } from '@kubb/core'\n\n/**\n * Returns the absolute output directory of `plugin` with a trailing separator,\n * suitable for prefix-based exclusion checks via {@link isExcludedPath}.\n *\n * The trailing `/` ensures `startsWith` does not match unrelated siblings\n * (e.g. `/foo/bar` vs `/foo/barbaz/x.ts`).\n */\nexport function getPluginOutputPrefix(plugin: NormalizedPlugin, config: Config): string {\n return `${resolve(config.root, config.output.path, plugin.options.output.path)}/`\n}\n\n/**\n * Returns `true` when `filePath` lies under any of the directory prefixes in `prefixes`.\n * Prefixes must already include a trailing separator (see {@link getPluginOutputPrefix}).\n *\n * Uses Node 22 iterator helpers (`Iterator.prototype.some`) to avoid materializing the set.\n */\nexport function isExcludedPath(filePath: string, prefixes: ReadonlySet<string>): boolean {\n return prefixes.values().some((prefix) => filePath.startsWith(prefix))\n}\n","import type { Config, NormalizedPlugin } from '@kubb/core'\nimport type { BarrelType } from '../types.ts'\n\nconst DEFAULT_BARREL_TYPE: BarrelType = 'named'\n\n/**\n * Resolves the effective barrel style for a single plugin: explicit plugin option →\n * root config option → `'named'` default. Returns `false` when barrel generation is disabled.\n */\nexport function resolvePluginBarrelType(plugin: NormalizedPlugin, config: Config): BarrelType | false {\n return plugin.options.output?.barrelType ?? config.output.barrelType ?? DEFAULT_BARREL_TYPE\n}\n\n/**\n * Resolves the effective barrel style for the root `index.ts`: root config option → `'named'` default.\n * Returns `false` when the root barrel is disabled.\n */\nexport function resolveRootBarrelType(config: Config): BarrelType | false {\n return config.output.barrelType ?? DEFAULT_BARREL_TYPE\n}\n","import { defineMiddleware } from '@kubb/core'\nimport type { KubbBuildStartContext } from '@kubb/core'\nimport type { BarrelType } from './types.ts'\nimport { generatePerPluginBarrel } from './utils/generatePerPluginBarrel.ts'\nimport { generateRootBarrel } from './utils/generateRootBarrel.ts'\nimport { getPluginOutputPrefix, isExcludedPath } from './utils/excludedPaths.ts'\nimport { resolvePluginBarrelType, resolveRootBarrelType } from './utils/resolveBarrelType.ts'\n\ndeclare global {\n namespace Kubb {\n interface PluginOptionsRegistry {\n output: {\n /**\n * Re-export style for this plugin's barrel file.\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.barrelType` when omitted.\n *\n * @default 'named'\n */\n barrelType?: BarrelType | false\n }\n }\n interface ConfigOptionsRegistry {\n output: {\n /**\n * Re-export style 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.barrelType`.\n *\n * @default 'named'\n */\n barrelType?: BarrelType | false\n }\n }\n }\n}\n\n/**\n * Generates `index.ts` barrel files for each plugin's output directory and one root barrel\n * at `config.output.path/index.ts`.\n *\n * Plugins inherit `output.barrelType` from `config.output.barrelType` (which itself defaults to `'named'`).\n * Setting `barrelType: false` on a plugin disables its barrel and excludes the plugin's files from the\n * root barrel as well.\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', barrelType: 'named' },\n * plugins: [\n * pluginTs({ output: { path: 'types', barrelType: 'all' } }),\n * pluginZod({ output: { path: 'schemas' } }),\n * ],\n * middleware: [middlewareBarrel],\n * })\n * ```\n */\nexport const middlewareBarrel = defineMiddleware({\n name: 'middleware-barrel',\n install(hooks) {\n let ctx: KubbBuildStartContext | undefined\n const excludedPrefixes = new Set<string>()\n\n hooks.on('kubb:build:start', (buildCtx) => {\n ctx = buildCtx\n })\n\n hooks.on('kubb:plugin:end', ({ plugin }) => {\n if (!ctx) return\n\n const barrelType = resolvePluginBarrelType(plugin, ctx.config)\n\n if (!barrelType) {\n excludedPrefixes.add(getPluginOutputPrefix(plugin, ctx.config))\n return\n }\n\n const barrelFiles = generatePerPluginBarrel({\n barrelType,\n plugin,\n files: ctx.files,\n config: ctx.config,\n })\n\n if (barrelFiles.length > 0) {\n ctx.upsertFile(...barrelFiles)\n }\n })\n\n hooks.on('kubb:plugins:end', ({ files, config, upsertFile }) => {\n const rootBarrelType = resolveRootBarrelType(config)\n if (!rootBarrelType) return\n\n const filteredFiles = excludedPrefixes.size === 0 ? files : files.filter((f) => !isExcludedPath(f.path, excludedPrefixes))\n\n const rootBarrelFiles = generateRootBarrel({\n barrelType: rootBarrelType,\n files: filteredFiles,\n config,\n })\n\n if (rootBarrelFiles.length > 0) {\n upsertFile(...rootBarrelFiles)\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/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 })\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<Exclude<BarrelType, 'propagate'>, 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 */\nfunction walkPropagate(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 walkPropagate(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\nexport type 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 * Re-export style 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 * - `'propagate'` emits one barrel per directory and chains sub-barrels\n */\n barrelType: BarrelType\n /**\n * Also generate a barrel for each sub-directory of `outputPath`.\n * No effect for `barrelType: 'propagate'`, which always recurses.\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, 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 if (barrelType === 'propagate') {\n walkPropagate(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 { resolve } from 'node:path'\nimport { defineMiddleware } from '@kubb/core'\nimport type { KubbBuildStartContext } from '@kubb/core'\nimport type { BarrelType } 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 * Re-export style for this plugin's barrel file.\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.barrelType` when omitted.\n *\n * @default 'named'\n */\n barrelType?: BarrelType | false\n }\n }\n interface ConfigOptionsRegistry {\n output: {\n /**\n * Re-export style 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.barrelType`.\n *\n * @default 'named'\n */\n barrelType?: BarrelType | false\n }\n }\n }\n}\n\n/**\n * Generates `index.ts` barrel files for each plugin's output directory and one root barrel\n * at `config.output.path/index.ts`.\n *\n * Plugins inherit `output.barrelType` from `config.output.barrelType` (which itself defaults to `'named'`).\n * Setting `barrelType: false` on a plugin disables its barrel and excludes the plugin's files from the\n * root barrel as well.\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', barrelType: 'named' },\n * plugins: [\n * pluginTs({ output: { path: 'types', barrelType: 'all' } }),\n * pluginZod({ output: { path: 'schemas' } }),\n * ],\n * middleware: [middlewareBarrel],\n * })\n * ```\n */\nexport const middlewareBarrel = defineMiddleware({\n name: 'middleware-barrel',\n install(hooks) {\n let ctx: KubbBuildStartContext | undefined\n const excludedPrefixes = new Set<string>()\n\n hooks.on('kubb:build:start', (buildCtx) => {\n ctx = buildCtx\n })\n\n hooks.on('kubb:plugin:end', ({ plugin }) => {\n if (!ctx) return\n\n const barrelType = plugin.options.output?.barrelType ?? ctx.config.output.barrelType ?? 'named'\n\n if (!barrelType) {\n excludedPrefixes.add(getPluginOutputPrefix(plugin, ctx.config))\n return\n }\n\n const barrelFiles = getBarrelFiles({\n outputPath: resolve(ctx.config.root, ctx.config.output.path, plugin.options.output.path),\n files: ctx.files,\n barrelType,\n recursive: true,\n })\n\n if (barrelFiles.length > 0) {\n ctx.upsertFile(...barrelFiles)\n }\n })\n\n hooks.on('kubb:plugins:end', ({ files, config, upsertFile }) => {\n const rootBarrelType = config.output.barrelType ?? 'named'\n if (!rootBarrelType) return\n\n const filteredFiles = excludedPrefixes.size === 0 ? files : files.filter((f) => !isExcludedPath(f.path, excludedPrefixes))\n\n const rootBarrelFiles = getBarrelFiles({\n outputPath: resolve(config.root, config.output.path),\n files: filteredFiles,\n barrelType: rootBarrelType,\n })\n\n if (rootBarrelFiles.length > 0) {\n upsertFile(...rootBarrelFiles)\n }\n })\n },\n})\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kubb/middleware-barrel",
|
|
3
|
-
"version": "5.0.0-alpha.
|
|
3
|
+
"version": "5.0.0-alpha.67",
|
|
4
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.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"barrel",
|
|
@@ -43,12 +43,12 @@
|
|
|
43
43
|
"access": "public",
|
|
44
44
|
"registry": "https://registry.npmjs.org/"
|
|
45
45
|
},
|
|
46
|
-
"peerDependencies": {
|
|
47
|
-
"@kubb/core": "5.0.0-alpha.65"
|
|
48
|
-
},
|
|
49
46
|
"devDependencies": {
|
|
50
47
|
"@internals/utils": "0.0.0"
|
|
51
48
|
},
|
|
49
|
+
"peerDependencies": {
|
|
50
|
+
"@kubb/core": "5.0.0-alpha.67"
|
|
51
|
+
},
|
|
52
52
|
"engines": {
|
|
53
53
|
"node": ">=22"
|
|
54
54
|
},
|
package/src/middleware.ts
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
|
+
import { resolve } from 'node:path'
|
|
1
2
|
import { defineMiddleware } from '@kubb/core'
|
|
2
3
|
import type { KubbBuildStartContext } from '@kubb/core'
|
|
3
4
|
import type { BarrelType } from './types.ts'
|
|
4
|
-
import { generatePerPluginBarrel } from './utils/generatePerPluginBarrel.ts'
|
|
5
|
-
import { generateRootBarrel } from './utils/generateRootBarrel.ts'
|
|
6
5
|
import { getPluginOutputPrefix, isExcludedPath } from './utils/excludedPaths.ts'
|
|
7
|
-
import {
|
|
6
|
+
import { getBarrelFiles } from './utils/getBarrelFiles.ts'
|
|
8
7
|
|
|
9
8
|
declare global {
|
|
10
9
|
namespace Kubb {
|
|
@@ -73,18 +72,18 @@ export const middlewareBarrel = defineMiddleware({
|
|
|
73
72
|
hooks.on('kubb:plugin:end', ({ plugin }) => {
|
|
74
73
|
if (!ctx) return
|
|
75
74
|
|
|
76
|
-
const barrelType =
|
|
75
|
+
const barrelType = plugin.options.output?.barrelType ?? ctx.config.output.barrelType ?? 'named'
|
|
77
76
|
|
|
78
77
|
if (!barrelType) {
|
|
79
78
|
excludedPrefixes.add(getPluginOutputPrefix(plugin, ctx.config))
|
|
80
79
|
return
|
|
81
80
|
}
|
|
82
81
|
|
|
83
|
-
const barrelFiles =
|
|
84
|
-
|
|
85
|
-
plugin,
|
|
82
|
+
const barrelFiles = getBarrelFiles({
|
|
83
|
+
outputPath: resolve(ctx.config.root, ctx.config.output.path, plugin.options.output.path),
|
|
86
84
|
files: ctx.files,
|
|
87
|
-
|
|
85
|
+
barrelType,
|
|
86
|
+
recursive: true,
|
|
88
87
|
})
|
|
89
88
|
|
|
90
89
|
if (barrelFiles.length > 0) {
|
|
@@ -93,15 +92,15 @@ export const middlewareBarrel = defineMiddleware({
|
|
|
93
92
|
})
|
|
94
93
|
|
|
95
94
|
hooks.on('kubb:plugins:end', ({ files, config, upsertFile }) => {
|
|
96
|
-
const rootBarrelType =
|
|
95
|
+
const rootBarrelType = config.output.barrelType ?? 'named'
|
|
97
96
|
if (!rootBarrelType) return
|
|
98
97
|
|
|
99
98
|
const filteredFiles = excludedPrefixes.size === 0 ? files : files.filter((f) => !isExcludedPath(f.path, excludedPrefixes))
|
|
100
99
|
|
|
101
|
-
const rootBarrelFiles =
|
|
102
|
-
|
|
100
|
+
const rootBarrelFiles = getBarrelFiles({
|
|
101
|
+
outputPath: resolve(config.root, config.output.path),
|
|
103
102
|
files: filteredFiles,
|
|
104
|
-
|
|
103
|
+
barrelType: rootBarrelType,
|
|
105
104
|
})
|
|
106
105
|
|
|
107
106
|
if (rootBarrelFiles.length > 0) {
|
|
@@ -1,23 +1,22 @@
|
|
|
1
1
|
import { resolve } from 'node:path'
|
|
2
2
|
import type { Config, NormalizedPlugin } from '@kubb/core'
|
|
3
|
+
import { toPosixPath } from '@internals/utils'
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
|
-
*
|
|
6
|
-
* suitable for prefix-based exclusion checks via {@link isExcludedPath}.
|
|
6
|
+
* Builds a POSIX-normalized prefix for a plugin's output directory, with a trailing `/`.
|
|
7
7
|
*
|
|
8
|
-
*
|
|
9
|
-
* (e.g. `/foo/bar` vs `/foo/barbaz/x.ts`).
|
|
8
|
+
* Used to detect (and later exclude) files generated by plugins that opted out of the root barrel.
|
|
10
9
|
*/
|
|
11
10
|
export function getPluginOutputPrefix(plugin: NormalizedPlugin, config: Config): string {
|
|
12
|
-
return `${resolve(config.root, config.output.path, plugin.options.output.path)}/`
|
|
11
|
+
return `${toPosixPath(resolve(config.root, config.output.path, plugin.options.output.path))}/`
|
|
13
12
|
}
|
|
14
13
|
|
|
15
14
|
/**
|
|
16
|
-
* Returns `true` when `filePath`
|
|
17
|
-
* Prefixes must already include a trailing separator (see {@link getPluginOutputPrefix}).
|
|
15
|
+
* Returns `true` when `filePath` lives under any of the given excluded directory prefixes.
|
|
18
16
|
*
|
|
19
|
-
*
|
|
17
|
+
* Both sides are POSIX-normalized so Windows backslash paths match correctly.
|
|
20
18
|
*/
|
|
21
19
|
export function isExcludedPath(filePath: string, prefixes: ReadonlySet<string>): boolean {
|
|
22
|
-
|
|
20
|
+
const normalized = toPosixPath(filePath)
|
|
21
|
+
return prefixes.values().some((prefix) => normalized.startsWith(prefix))
|
|
23
22
|
}
|
|
@@ -3,21 +3,11 @@ import { createExport, createFile } from '@kubb/ast'
|
|
|
3
3
|
import type { ExportNode, FileNode, SourceNode } from '@kubb/ast'
|
|
4
4
|
import { BARREL_FILENAME } from '../constants.ts'
|
|
5
5
|
import type { BarrelType } from '../types.ts'
|
|
6
|
-
import { type BuildTree, buildTree } from '@internals/utils'
|
|
6
|
+
import { type BuildTree, buildTree, toPosixPath } from '@internals/utils'
|
|
7
7
|
|
|
8
8
|
const SOURCE_EXTENSIONS = new Set(['.ts', '.tsx', '.js', '.jsx'])
|
|
9
9
|
const BARREL_SUFFIX = `/${BARREL_FILENAME}`
|
|
10
10
|
|
|
11
|
-
/**
|
|
12
|
-
* Derives a relative module specifier from `filePath` relative to `fromDir`.
|
|
13
|
-
* The source extension is preserved so `@kubb/parser-ts` can apply its `extNames` mapping.
|
|
14
|
-
*
|
|
15
|
-
* @example
|
|
16
|
-
* ```ts
|
|
17
|
-
* toRelativeModulePath('/src/gen/types', '/src/gen/types/pet.ts') // './pet.ts'
|
|
18
|
-
* toRelativeModulePath('/src/gen/types', '/src/gen/types/tags/tag.ts') // './tags/tag.ts'
|
|
19
|
-
* ```
|
|
20
|
-
*/
|
|
21
11
|
function toRelativeModulePath(fromDir: string, filePath: string): string {
|
|
22
12
|
return `./${filePath.slice(fromDir.length + 1)}`
|
|
23
13
|
}
|
|
@@ -105,8 +95,7 @@ type LeafWalkParams = {
|
|
|
105
95
|
}
|
|
106
96
|
|
|
107
97
|
/**
|
|
108
|
-
*
|
|
109
|
-
* returns its leaf paths so parents don't have to re-walk the subtree.
|
|
98
|
+
* Post-order walk that emits a barrel per visited directory.
|
|
110
99
|
*/
|
|
111
100
|
function walkAllOrNamed(node: BuildTree, params: LeafWalkParams, isRoot: boolean, out: Array<FileNode>): Array<string> {
|
|
112
101
|
const subtreeLeaves: Array<string> = []
|
|
@@ -121,7 +110,6 @@ function walkAllOrNamed(node: BuildTree, params: LeafWalkParams, isRoot: boolean
|
|
|
121
110
|
for (const leaf of childLeaves) subtreeLeaves.push(leaf)
|
|
122
111
|
}
|
|
123
112
|
|
|
124
|
-
// Sub-directory barrels are only emitted when the caller asked for them.
|
|
125
113
|
if (!isRoot && !params.recursive) return subtreeLeaves
|
|
126
114
|
|
|
127
115
|
const exports = subtreeLeaves.flatMap((leafPath) => params.strategy({ dirPath: node.path, leafPath, sourceFile: params.sourceFiles.get(leafPath) }))
|
|
@@ -134,8 +122,7 @@ function walkAllOrNamed(node: BuildTree, params: LeafWalkParams, isRoot: boolean
|
|
|
134
122
|
}
|
|
135
123
|
|
|
136
124
|
/**
|
|
137
|
-
*
|
|
138
|
-
* sub-directory is re-exported via its own barrel (recursive by design).
|
|
125
|
+
* Recursive walk that emits one barrel per directory, re-exporting files and sub-barrels.
|
|
139
126
|
*/
|
|
140
127
|
function walkPropagate(node: BuildTree, out: Array<FileNode>): void {
|
|
141
128
|
const exports: Array<ExportNode> = []
|
|
@@ -157,29 +144,23 @@ function walkPropagate(node: BuildTree, out: Array<FileNode>): void {
|
|
|
157
144
|
}
|
|
158
145
|
|
|
159
146
|
type IndexedFiles = {
|
|
160
|
-
/**
|
|
161
|
-
* `path → FileNode` lookup limited to files that participate in barrel generation.
|
|
162
|
-
*/
|
|
163
147
|
sourceFiles: ReadonlyMap<string, FileNode>
|
|
164
|
-
/**
|
|
165
|
-
* Original (un-normalized) paths of `sourceFiles`, in input order — used as input for {@link buildTree}.
|
|
166
|
-
*/
|
|
167
148
|
paths: ReadonlyArray<string>
|
|
168
149
|
}
|
|
169
150
|
|
|
170
151
|
function indexRelevantFiles(files: ReadonlyArray<FileNode>, outputPath: string): IndexedFiles {
|
|
171
|
-
const outputPrefix = `${outputPath
|
|
152
|
+
const outputPrefix = `${toPosixPath(outputPath)}/`
|
|
172
153
|
const sourceFiles = new Map<string, FileNode>()
|
|
173
154
|
const paths: Array<string> = []
|
|
174
155
|
|
|
175
156
|
for (const file of files) {
|
|
176
|
-
const normalized = file.path
|
|
157
|
+
const normalized = toPosixPath(file.path)
|
|
177
158
|
if (!normalized.startsWith(outputPrefix)) continue
|
|
178
159
|
if (isBarrelPath(normalized)) continue
|
|
179
160
|
if (!SOURCE_EXTENSIONS.has(extname(normalized))) continue
|
|
180
161
|
|
|
181
|
-
sourceFiles.set(
|
|
182
|
-
paths.push(
|
|
162
|
+
sourceFiles.set(normalized, file)
|
|
163
|
+
paths.push(normalized)
|
|
183
164
|
}
|
|
184
165
|
|
|
185
166
|
return { sourceFiles, paths }
|
|
@@ -187,24 +168,24 @@ function indexRelevantFiles(files: ReadonlyArray<FileNode>, outputPath: string):
|
|
|
187
168
|
|
|
188
169
|
export type GetBarrelFilesParams = {
|
|
189
170
|
/**
|
|
190
|
-
* Absolute
|
|
191
|
-
*
|
|
171
|
+
* Absolute directory the barrel(s) should be rooted at.
|
|
172
|
+
* Only files living under this path are considered.
|
|
192
173
|
*/
|
|
193
174
|
outputPath: string
|
|
194
175
|
/**
|
|
195
|
-
*
|
|
196
|
-
* Used both to discover what to re-export and to read each file's indexable sources.
|
|
176
|
+
* Pool of generated files to scan for indexable sources.
|
|
197
177
|
*/
|
|
198
178
|
files: ReadonlyArray<FileNode>
|
|
199
179
|
/**
|
|
200
|
-
* Re-export style used
|
|
180
|
+
* Re-export style used when emitting each barrel.
|
|
181
|
+
* - `'all'` re-exports the whole module (`export * from './x'`)
|
|
182
|
+
* - `'named'` re-exports only the indexable named symbols
|
|
183
|
+
* - `'propagate'` emits one barrel per directory and chains sub-barrels
|
|
201
184
|
*/
|
|
202
185
|
barrelType: BarrelType
|
|
203
186
|
/**
|
|
204
|
-
*
|
|
205
|
-
*
|
|
206
|
-
*
|
|
207
|
-
* Has no effect for `barrelType: 'propagate'`, which always recurses by design.
|
|
187
|
+
* Also generate a barrel for each sub-directory of `outputPath`.
|
|
188
|
+
* No effect for `barrelType: 'propagate'`, which always recurses.
|
|
208
189
|
*
|
|
209
190
|
* @default false
|
|
210
191
|
*/
|
|
@@ -213,9 +194,6 @@ export type GetBarrelFilesParams = {
|
|
|
213
194
|
|
|
214
195
|
/**
|
|
215
196
|
* Generates barrel `FileNode`s for the directory rooted at `outputPath`.
|
|
216
|
-
*
|
|
217
|
-
* Files outside `outputPath`, existing barrel files, and non-source extensions are filtered out
|
|
218
|
-
* before the tree is built.
|
|
219
197
|
*/
|
|
220
198
|
export function getBarrelFiles({ outputPath, files, barrelType, recursive = false }: GetBarrelFilesParams): Array<FileNode> {
|
|
221
199
|
const { sourceFiles, paths } = indexRelevantFiles(files, outputPath)
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
import { resolve } from 'node:path'
|
|
2
|
-
import type { FileNode } from '@kubb/ast'
|
|
3
|
-
import type { Config, NormalizedPlugin } from '@kubb/core'
|
|
4
|
-
import type { BarrelType } from '../types.ts'
|
|
5
|
-
import { getBarrelFiles } from './getBarrelFiles.ts'
|
|
6
|
-
|
|
7
|
-
export type GeneratePerPluginBarrelParams = {
|
|
8
|
-
/**
|
|
9
|
-
* Re-export style used in the plugin's barrel file(s).
|
|
10
|
-
*/
|
|
11
|
-
barrelType: BarrelType
|
|
12
|
-
/**
|
|
13
|
-
* Plugin whose `output.path` determines the barrel directory.
|
|
14
|
-
*/
|
|
15
|
-
plugin: NormalizedPlugin
|
|
16
|
-
/**
|
|
17
|
-
* Full set of generated files across all plugins.
|
|
18
|
-
* Files outside the plugin's output directory are filtered out automatically.
|
|
19
|
-
*/
|
|
20
|
-
files: ReadonlyArray<FileNode>
|
|
21
|
-
/**
|
|
22
|
-
* Resolved Kubb config; used to compute the absolute output directory.
|
|
23
|
-
*/
|
|
24
|
-
config: Config
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Generates barrel files for a single plugin's output directory.
|
|
29
|
-
*
|
|
30
|
-
* The barrel is placed at `<config.root>/<config.output.path>/<plugin.options.output.path>/index.ts`.
|
|
31
|
-
* When the plugin uses `group`, additional sub-directory barrels are generated so that grouped
|
|
32
|
-
* output (e.g. `petController/index.ts`) gets its own re-export entry point.
|
|
33
|
-
*/
|
|
34
|
-
export function generatePerPluginBarrel({ barrelType, plugin, files, config }: GeneratePerPluginBarrelParams): Array<FileNode> {
|
|
35
|
-
const outputPath = resolve(config.root, config.output.path, plugin.options.output.path)
|
|
36
|
-
|
|
37
|
-
return getBarrelFiles({ outputPath, files, barrelType, recursive: true })
|
|
38
|
-
}
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
import { resolve } from 'node:path'
|
|
2
|
-
import type { FileNode } from '@kubb/ast'
|
|
3
|
-
import type { Config } from '@kubb/core'
|
|
4
|
-
import type { BarrelType } from '../types.ts'
|
|
5
|
-
import { getBarrelFiles } from './getBarrelFiles.ts'
|
|
6
|
-
|
|
7
|
-
export type GenerateRootBarrelParams = {
|
|
8
|
-
/**
|
|
9
|
-
* Re-export style used in the root barrel file.
|
|
10
|
-
*/
|
|
11
|
-
barrelType: BarrelType
|
|
12
|
-
/**
|
|
13
|
-
* Files eligible for re-export. The middleware filters out files belonging to plugins
|
|
14
|
-
* with `barrelType: false` before passing them in.
|
|
15
|
-
*/
|
|
16
|
-
files: ReadonlyArray<FileNode>
|
|
17
|
-
/**
|
|
18
|
-
* Resolved Kubb config; used to compute the root output directory.
|
|
19
|
-
*/
|
|
20
|
-
config: Config
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Generates the root barrel file at `<config.root>/<config.output.path>/index.ts`.
|
|
25
|
-
*
|
|
26
|
-
* Unlike `generatePerPluginBarrel`, this does not recurse into sub-directories — each
|
|
27
|
-
* plugin is responsible for its own per-plugin barrels.
|
|
28
|
-
*/
|
|
29
|
-
export function generateRootBarrel({ barrelType, files, config }: GenerateRootBarrelParams): Array<FileNode> {
|
|
30
|
-
const outputPath = resolve(config.root, config.output.path)
|
|
31
|
-
|
|
32
|
-
return getBarrelFiles({ outputPath, files, barrelType })
|
|
33
|
-
}
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import type { Config, NormalizedPlugin } from '@kubb/core'
|
|
2
|
-
import type { BarrelType } from '../types.ts'
|
|
3
|
-
|
|
4
|
-
const DEFAULT_BARREL_TYPE: BarrelType = 'named'
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* Resolves the effective barrel style for a single plugin: explicit plugin option →
|
|
8
|
-
* root config option → `'named'` default. Returns `false` when barrel generation is disabled.
|
|
9
|
-
*/
|
|
10
|
-
export function resolvePluginBarrelType(plugin: NormalizedPlugin, config: Config): BarrelType | false {
|
|
11
|
-
return plugin.options.output?.barrelType ?? config.output.barrelType ?? DEFAULT_BARREL_TYPE
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Resolves the effective barrel style for the root `index.ts`: root config option → `'named'` default.
|
|
16
|
-
* Returns `false` when the root barrel is disabled.
|
|
17
|
-
*/
|
|
18
|
-
export function resolveRootBarrelType(config: Config): BarrelType | false {
|
|
19
|
-
return config.output.barrelType ?? DEFAULT_BARREL_TYPE
|
|
20
|
-
}
|