@kubb/middleware-barrel 5.0.0-alpha.62 → 5.0.0-alpha.64
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 +213 -159
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +20 -29
- package/dist/index.js +214 -160
- package/dist/index.js.map +1 -1
- package/package.json +5 -2
- package/src/constants.ts +0 -1
- package/src/middleware.ts +23 -33
- package/src/types.ts +5 -7
- package/src/utils/excludedPaths.ts +23 -0
- package/src/utils/generatePerPluginBarrel.ts +17 -7
- package/src/utils/generateRootBarrel.ts +14 -7
- package/src/utils/getBarrelFiles.ts +183 -154
- package/src/utils/resolveBarrelType.ts +20 -0
- package/src/utils/buildTree.ts +0 -67
package/dist/index.d.ts
CHANGED
|
@@ -3,12 +3,11 @@ import * as _$_kubb_core0 from "@kubb/core";
|
|
|
3
3
|
|
|
4
4
|
//#region src/types.d.ts
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* - `'
|
|
9
|
-
* - `'
|
|
10
|
-
*
|
|
11
|
-
* every sub-directory so that consumers can import from any depth.
|
|
6
|
+
* Re-export style used when generating barrel `index.ts` files.
|
|
7
|
+
* - `'all'` emits `export * from '...'` for every file.
|
|
8
|
+
* - `'named'` emits `export { name1, name2 } from '...'` from each file's indexable sources.
|
|
9
|
+
* - `'propagate'` behaves like `'all'` and also generates an intermediate barrel for every
|
|
10
|
+
* sub-directory so consumers can import from any depth.
|
|
12
11
|
*/
|
|
13
12
|
type BarrelType = 'all' | 'named' | 'propagate';
|
|
14
13
|
//#endregion
|
|
@@ -18,14 +17,13 @@ declare global {
|
|
|
18
17
|
interface PluginOptionsRegistry {
|
|
19
18
|
output: {
|
|
20
19
|
/**
|
|
21
|
-
*
|
|
20
|
+
* Re-export style for this plugin's barrel file.
|
|
21
|
+
* Set to `false` to disable barrel generation for this plugin entirely; doing so also
|
|
22
|
+
* excludes the plugin's files from the root barrel.
|
|
22
23
|
*
|
|
23
|
-
*
|
|
24
|
-
* - `'named'` — `export { … } from '...'` using the file's named exports.
|
|
25
|
-
* - `'propagate'` — like `'all'` but also generates intermediate barrel files.
|
|
26
|
-
* - `false` — disable barrel generation for this plugin.
|
|
24
|
+
* Falls back to `config.output.barrelType` when omitted.
|
|
27
25
|
*
|
|
28
|
-
*
|
|
26
|
+
* @default 'named'
|
|
29
27
|
*/
|
|
30
28
|
barrelType?: BarrelType | false;
|
|
31
29
|
};
|
|
@@ -33,14 +31,11 @@ declare global {
|
|
|
33
31
|
interface ConfigOptionsRegistry {
|
|
34
32
|
output: {
|
|
35
33
|
/**
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
* - `'named'` — `export { … } from '...'` using the barrel's named exports.
|
|
40
|
-
* - `'propagate'` — like `'all'` but also generates intermediate barrel files.
|
|
41
|
-
* - `false` — disable root barrel generation.
|
|
34
|
+
* Re-export style for the root barrel file at `config.output.path/index.ts`.
|
|
35
|
+
* Set to `false` to disable root barrel generation. Individual plugins can override
|
|
36
|
+
* this via their own `output.barrelType`.
|
|
42
37
|
*
|
|
43
|
-
*
|
|
38
|
+
* @default 'named'
|
|
44
39
|
*/
|
|
45
40
|
barrelType?: BarrelType | false;
|
|
46
41
|
};
|
|
@@ -48,20 +43,16 @@ declare global {
|
|
|
48
43
|
}
|
|
49
44
|
}
|
|
50
45
|
/**
|
|
51
|
-
*
|
|
52
|
-
*
|
|
53
|
-
* When added to `config.middleware`, generates an `index.ts` barrel file for each
|
|
54
|
-
* plugin. When `output.barrelType` is omitted on a plugin it inherits from `config.output.barrelType`,
|
|
55
|
-
* and when that is also omitted both default to `'all'`. Set `barrelType: false` to disable
|
|
56
|
-
* barrel generation for a specific plugin or for the root entirely.
|
|
46
|
+
* Generates `index.ts` barrel files for each plugin's output directory and one root barrel
|
|
47
|
+
* at `config.output.path/index.ts`.
|
|
57
48
|
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
* - `'propagate'` — like `'all'` with intermediate barrel files for sub-directories
|
|
49
|
+
* Plugins inherit `output.barrelType` from `config.output.barrelType` (which itself defaults to `'named'`).
|
|
50
|
+
* Setting `barrelType: false` on a plugin disables its barrel and excludes the plugin's files from the
|
|
51
|
+
* root barrel as well.
|
|
62
52
|
*
|
|
63
53
|
* @example
|
|
64
54
|
* ```ts
|
|
55
|
+
* import { defineConfig } from '@kubb/core'
|
|
65
56
|
* import { middlewareBarrel } from '@kubb/middleware-barrel'
|
|
66
57
|
*
|
|
67
58
|
* export default defineConfig({
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import "./chunk--u3MIqq1.js";
|
|
2
2
|
import { defineMiddleware } from "@kubb/core";
|
|
3
|
-
import {
|
|
3
|
+
import { extname, resolve } from "node:path";
|
|
4
4
|
import { createExport, createFile } from "@kubb/ast";
|
|
5
5
|
//#region src/constants.ts
|
|
6
6
|
/**
|
|
@@ -8,18 +8,18 @@ import { createExport, createFile } from "@kubb/ast";
|
|
|
8
8
|
*/
|
|
9
9
|
const BARREL_FILENAME = "index.ts";
|
|
10
10
|
//#endregion
|
|
11
|
-
//#region
|
|
11
|
+
//#region ../../internals/utils/src/buildTree.ts
|
|
12
12
|
/**
|
|
13
|
-
* Builds a
|
|
13
|
+
* Builds a directory tree rooted at `rootPath` from a list of absolute file paths.
|
|
14
|
+
* Paths outside `rootPath` are silently ignored. Children are sorted alphabetically
|
|
15
|
+
* by path so consumers (barrel exports, propagated indexes) emit a deterministic order.
|
|
14
16
|
*
|
|
15
|
-
*
|
|
16
|
-
* the root or that equal the root are silently ignored.
|
|
17
|
+
* Both POSIX (`/`) and Windows (`\`) separators are accepted in input paths.
|
|
17
18
|
*
|
|
18
19
|
* @example
|
|
19
20
|
* ```ts
|
|
20
|
-
*
|
|
21
|
+
* buildTree('/src/gen/types', [
|
|
21
22
|
* '/src/gen/types/pet.ts',
|
|
22
|
-
* '/src/gen/types/user.ts',
|
|
23
23
|
* '/src/gen/types/pets/listPets.ts',
|
|
24
24
|
* ])
|
|
25
25
|
* ```
|
|
@@ -30,28 +30,45 @@ function buildTree(rootPath, filePaths) {
|
|
|
30
30
|
children: [],
|
|
31
31
|
isFile: false
|
|
32
32
|
};
|
|
33
|
+
const childIndex = /* @__PURE__ */ new Map();
|
|
34
|
+
childIndex.set(root, /* @__PURE__ */ new Map());
|
|
35
|
+
const rootPrefix = `${rootPath.replaceAll("\\", "/")}/`;
|
|
33
36
|
for (const filePath of filePaths) {
|
|
34
|
-
|
|
35
|
-
|
|
37
|
+
const normalized = filePath.replaceAll("\\", "/");
|
|
38
|
+
if (!normalized.startsWith(rootPrefix)) continue;
|
|
39
|
+
const parts = normalized.slice(rootPrefix.length).split("/");
|
|
40
|
+
if (parts.length === 0) continue;
|
|
36
41
|
let current = root;
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
const
|
|
41
|
-
|
|
42
|
+
const lastIndex = parts.length - 1;
|
|
43
|
+
for (const [i, part] of parts.entries()) {
|
|
44
|
+
if (!part) continue;
|
|
45
|
+
const isLast = i === lastIndex;
|
|
46
|
+
const siblings = childIndex.get(current);
|
|
47
|
+
let child = siblings.get(part);
|
|
42
48
|
if (!child) {
|
|
43
49
|
child = {
|
|
44
|
-
path:
|
|
50
|
+
path: `${current.path}/${part}`,
|
|
45
51
|
children: [],
|
|
46
52
|
isFile: isLast
|
|
47
53
|
};
|
|
48
54
|
current.children.push(child);
|
|
55
|
+
siblings.set(part, child);
|
|
56
|
+
if (!isLast) childIndex.set(child, /* @__PURE__ */ new Map());
|
|
49
57
|
}
|
|
50
58
|
current = child;
|
|
51
59
|
}
|
|
52
60
|
}
|
|
61
|
+
sortTree(root);
|
|
53
62
|
return root;
|
|
54
63
|
}
|
|
64
|
+
function sortTree(node) {
|
|
65
|
+
if (node.children.length === 0) return;
|
|
66
|
+
node.children.sort(compareByPath);
|
|
67
|
+
for (const child of node.children) if (!child.isFile) sortTree(child);
|
|
68
|
+
}
|
|
69
|
+
function compareByPath(a, b) {
|
|
70
|
+
return a.path < b.path ? -1 : a.path > b.path ? 1 : 0;
|
|
71
|
+
}
|
|
55
72
|
//#endregion
|
|
56
73
|
//#region src/utils/getBarrelFiles.ts
|
|
57
74
|
const SOURCE_EXTENSIONS = new Set([
|
|
@@ -60,199 +77,236 @@ const SOURCE_EXTENSIONS = new Set([
|
|
|
60
77
|
".js",
|
|
61
78
|
".jsx"
|
|
62
79
|
]);
|
|
80
|
+
const BARREL_SUFFIX = `/${BARREL_FILENAME}`;
|
|
63
81
|
/**
|
|
64
|
-
* Derives a relative module specifier from
|
|
65
|
-
* The source extension is preserved so
|
|
66
|
-
* (e.g. `.ts` → `.js` for ESM output).
|
|
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.
|
|
67
84
|
*
|
|
68
85
|
* @example
|
|
86
|
+
* ```ts
|
|
69
87
|
* toRelativeModulePath('/src/gen/types', '/src/gen/types/pet.ts') // './pet.ts'
|
|
70
88
|
* toRelativeModulePath('/src/gen/types', '/src/gen/types/tags/tag.ts') // './tags/tag.ts'
|
|
89
|
+
* ```
|
|
71
90
|
*/
|
|
72
91
|
function toRelativeModulePath(fromDir, filePath) {
|
|
73
|
-
return `./${filePath.slice(fromDir.length
|
|
92
|
+
return `./${filePath.slice(fromDir.length + 1)}`;
|
|
74
93
|
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
* with their full relative path from `treeNode.path`.
|
|
81
|
-
*/
|
|
82
|
-
function getBarrelFilesAll(treeNode, sourceFiles) {
|
|
83
|
-
const leafPaths = collectLeafPaths(treeNode).filter((p) => !p.endsWith(`/${BARREL_FILENAME}`));
|
|
84
|
-
if (leafPaths.length === 0) return [];
|
|
85
|
-
const barrelPath = `${treeNode.path}/${BARREL_FILENAME}`;
|
|
86
|
-
const exports = [];
|
|
87
|
-
for (const filePath of leafPaths) {
|
|
88
|
-
const sourceFile = sourceFiles.find((f) => f.path === filePath);
|
|
89
|
-
if (sourceFile && sourceFile.sources.length > 0 && sourceFile.sources.every((s) => !s.isIndexable)) continue;
|
|
90
|
-
exports.push(createExport({ path: toRelativeModulePath(treeNode.path, filePath) }));
|
|
91
|
-
}
|
|
92
|
-
if (exports.length === 0) return [];
|
|
93
|
-
return [createFile({
|
|
94
|
+
function isBarrelPath(path) {
|
|
95
|
+
return path.endsWith(BARREL_SUFFIX);
|
|
96
|
+
}
|
|
97
|
+
function makeBarrel(dirPath, exports) {
|
|
98
|
+
return createFile({
|
|
94
99
|
baseName: BARREL_FILENAME,
|
|
95
|
-
path:
|
|
100
|
+
path: `${dirPath}${BARREL_SUFFIX}`,
|
|
96
101
|
exports,
|
|
97
102
|
sources: [],
|
|
98
103
|
imports: []
|
|
99
|
-
})
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
function hasOnlyNonIndexableSources(sources) {
|
|
107
|
+
if (sources.length === 0) return false;
|
|
108
|
+
for (const source of sources) if (source.isIndexable) return false;
|
|
109
|
+
return true;
|
|
100
110
|
}
|
|
111
|
+
function partitionIndexableNames(sources) {
|
|
112
|
+
const byTypeOnly = new Map([[false, /* @__PURE__ */ new Set()], [true, /* @__PURE__ */ new Set()]]);
|
|
113
|
+
for (const source of sources) {
|
|
114
|
+
if (!source.isIndexable || !source.name) continue;
|
|
115
|
+
byTypeOnly.get(Boolean(source.isTypeOnly)).add(source.name);
|
|
116
|
+
}
|
|
117
|
+
return byTypeOnly;
|
|
118
|
+
}
|
|
119
|
+
const allStrategy = ({ dirPath, leafPath, sourceFile }) => {
|
|
120
|
+
if (sourceFile && hasOnlyNonIndexableSources(sourceFile.sources)) return [];
|
|
121
|
+
return [createExport({ path: toRelativeModulePath(dirPath, leafPath) })];
|
|
122
|
+
};
|
|
123
|
+
const namedStrategy = ({ dirPath, leafPath, sourceFile }) => {
|
|
124
|
+
const modulePath = toRelativeModulePath(dirPath, leafPath);
|
|
125
|
+
if (!sourceFile) return [createExport({ path: modulePath })];
|
|
126
|
+
const namesByTypeOnly = partitionIndexableNames(sourceFile.sources);
|
|
127
|
+
const valueNames = namesByTypeOnly.get(false);
|
|
128
|
+
const typeNames = namesByTypeOnly.get(true);
|
|
129
|
+
if (valueNames.size === 0 && typeNames.size === 0) {
|
|
130
|
+
if (sourceFile.sources.length > 0) return [];
|
|
131
|
+
return [createExport({ path: modulePath })];
|
|
132
|
+
}
|
|
133
|
+
const exports = [];
|
|
134
|
+
if (valueNames.size > 0) exports.push(createExport({
|
|
135
|
+
name: [...valueNames],
|
|
136
|
+
path: modulePath
|
|
137
|
+
}));
|
|
138
|
+
if (typeNames.size > 0) exports.push(createExport({
|
|
139
|
+
name: [...typeNames],
|
|
140
|
+
path: modulePath,
|
|
141
|
+
isTypeOnly: true
|
|
142
|
+
}));
|
|
143
|
+
return exports;
|
|
144
|
+
};
|
|
145
|
+
const LEAF_STRATEGIES = new Map([["all", allStrategy], ["named", namedStrategy]]);
|
|
101
146
|
/**
|
|
102
|
-
*
|
|
103
|
-
*
|
|
147
|
+
* Single-pass post-order traversal that emits a barrel for each visited directory and
|
|
148
|
+
* returns its leaf paths so parents don't have to re-walk the subtree.
|
|
104
149
|
*/
|
|
105
|
-
function
|
|
106
|
-
const
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
for (const filePath of leafPaths) {
|
|
111
|
-
const sourceFile = sourceFiles.find((f) => f.path === filePath);
|
|
112
|
-
if (!sourceFile) {
|
|
113
|
-
exports.push(createExport({ path: toRelativeModulePath(treeNode.path, filePath) }));
|
|
150
|
+
function walkAllOrNamed(node, params, isRoot, out) {
|
|
151
|
+
const subtreeLeaves = [];
|
|
152
|
+
for (const child of node.children) {
|
|
153
|
+
if (child.isFile) {
|
|
154
|
+
if (!isBarrelPath(child.path)) subtreeLeaves.push(child.path);
|
|
114
155
|
continue;
|
|
115
156
|
}
|
|
116
|
-
const
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
157
|
+
const childLeaves = walkAllOrNamed(child, params, false, out);
|
|
158
|
+
for (const leaf of childLeaves) subtreeLeaves.push(leaf);
|
|
159
|
+
}
|
|
160
|
+
if (!isRoot && !params.recursive) return subtreeLeaves;
|
|
161
|
+
const exports = subtreeLeaves.flatMap((leafPath) => params.strategy({
|
|
162
|
+
dirPath: node.path,
|
|
163
|
+
leafPath,
|
|
164
|
+
sourceFile: params.sourceFiles.get(leafPath)
|
|
165
|
+
}));
|
|
166
|
+
if (exports.length > 0) out.push(makeBarrel(node.path, exports));
|
|
167
|
+
return subtreeLeaves;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Emits one barrel per directory: every direct child file is re-exported and every
|
|
171
|
+
* sub-directory is re-exported via its own barrel (recursive by design).
|
|
172
|
+
*/
|
|
173
|
+
function walkPropagate(node, out) {
|
|
174
|
+
const exports = [];
|
|
175
|
+
for (const child of node.children) {
|
|
176
|
+
if (child.isFile) {
|
|
177
|
+
if (isBarrelPath(child.path)) continue;
|
|
178
|
+
exports.push(createExport({ path: toRelativeModulePath(node.path, child.path) }));
|
|
120
179
|
continue;
|
|
121
180
|
}
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
const modulePath = toRelativeModulePath(treeNode.path, filePath);
|
|
125
|
-
if (valueNames.length > 0) exports.push(createExport({
|
|
126
|
-
name: valueNames,
|
|
127
|
-
path: modulePath
|
|
128
|
-
}));
|
|
129
|
-
if (typeNames.length > 0) exports.push(createExport({
|
|
130
|
-
name: typeNames,
|
|
131
|
-
path: modulePath,
|
|
132
|
-
isTypeOnly: true
|
|
133
|
-
}));
|
|
181
|
+
walkPropagate(child, out);
|
|
182
|
+
exports.push(createExport({ path: toRelativeModulePath(node.path, `${child.path}${BARREL_SUFFIX}`) }));
|
|
134
183
|
}
|
|
135
|
-
if (exports.length
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
184
|
+
if (exports.length > 0) out.push(makeBarrel(node.path, exports));
|
|
185
|
+
}
|
|
186
|
+
function indexRelevantFiles(files, outputPath) {
|
|
187
|
+
const outputPrefix = `${outputPath.replaceAll("\\", "/")}/`;
|
|
188
|
+
const sourceFiles = /* @__PURE__ */ new Map();
|
|
189
|
+
const paths = [];
|
|
190
|
+
for (const file of files) {
|
|
191
|
+
const normalized = file.path.replaceAll("\\", "/");
|
|
192
|
+
if (!normalized.startsWith(outputPrefix)) continue;
|
|
193
|
+
if (isBarrelPath(normalized)) continue;
|
|
194
|
+
if (!SOURCE_EXTENSIONS.has(extname(normalized))) continue;
|
|
195
|
+
sourceFiles.set(file.path, file);
|
|
196
|
+
paths.push(file.path);
|
|
197
|
+
}
|
|
198
|
+
return {
|
|
199
|
+
sourceFiles,
|
|
200
|
+
paths
|
|
201
|
+
};
|
|
143
202
|
}
|
|
144
203
|
/**
|
|
145
|
-
* Generates barrel `FileNode
|
|
146
|
-
* like `'all'` but also generates intermediate barrel files for every sub-directory, so that
|
|
147
|
-
* consumers can import from any depth.
|
|
204
|
+
* Generates barrel `FileNode`s for the directory rooted at `outputPath`.
|
|
148
205
|
*
|
|
149
|
-
*
|
|
206
|
+
* Files outside `outputPath`, existing barrel files, and non-source extensions are filtered out
|
|
207
|
+
* before the tree is built.
|
|
150
208
|
*/
|
|
151
|
-
function
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
209
|
+
function getBarrelFiles({ outputPath, files, barrelType, recursive = false }) {
|
|
210
|
+
const { sourceFiles, paths } = indexRelevantFiles(files, outputPath);
|
|
211
|
+
if (paths.length === 0) return [];
|
|
212
|
+
const tree = buildTree(outputPath, paths);
|
|
155
213
|
const result = [];
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
} else {
|
|
160
|
-
const subBarrels = collectPropagatedBarrels(child);
|
|
161
|
-
result.push(...subBarrels);
|
|
162
|
-
const subBarrelPath = `${child.path}/${BARREL_FILENAME}`;
|
|
163
|
-
barrelExports.push(createExport({ path: toRelativeModulePath(node.path, subBarrelPath) }));
|
|
214
|
+
if (barrelType === "propagate") {
|
|
215
|
+
walkPropagate(tree, result);
|
|
216
|
+
return result;
|
|
164
217
|
}
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
})
|
|
218
|
+
const strategy = LEAF_STRATEGIES.get(barrelType);
|
|
219
|
+
if (!strategy) return result;
|
|
220
|
+
walkAllOrNamed(tree, {
|
|
221
|
+
sourceFiles,
|
|
222
|
+
strategy,
|
|
223
|
+
recursive
|
|
224
|
+
}, true, result);
|
|
172
225
|
return result;
|
|
173
226
|
}
|
|
227
|
+
//#endregion
|
|
228
|
+
//#region src/utils/generatePerPluginBarrel.ts
|
|
174
229
|
/**
|
|
175
|
-
*
|
|
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.
|
|
176
235
|
*/
|
|
177
|
-
function
|
|
178
|
-
|
|
179
|
-
|
|
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
|
+
});
|
|
180
243
|
}
|
|
244
|
+
//#endregion
|
|
245
|
+
//#region src/utils/generateRootBarrel.ts
|
|
181
246
|
/**
|
|
182
|
-
* Generates
|
|
183
|
-
* generated source `files`, using the specified `barrelType` strategy.
|
|
247
|
+
* Generates the root barrel file at `<config.root>/<config.output.path>/index.ts`.
|
|
184
248
|
*
|
|
185
|
-
*
|
|
186
|
-
*
|
|
187
|
-
* @param outputPath Absolute path to the output directory.
|
|
188
|
-
* @param files All generated files (across all plugins).
|
|
189
|
-
* @param barrelType Barrel generation strategy.
|
|
249
|
+
* Unlike `generatePerPluginBarrel`, this does not recurse into sub-directories — each
|
|
250
|
+
* plugin is responsible for its own per-plugin barrels.
|
|
190
251
|
*/
|
|
191
|
-
function
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
if (normalizedFilePath.endsWith(`/index.ts`)) return false;
|
|
197
|
-
const dotIndex = normalizedFilePath.lastIndexOf(".");
|
|
198
|
-
const ext = dotIndex === -1 ? "" : normalizedFilePath.slice(dotIndex);
|
|
199
|
-
return SOURCE_EXTENSIONS.has(ext);
|
|
252
|
+
function generateRootBarrel({ barrelType, files, config }) {
|
|
253
|
+
return getBarrelFiles({
|
|
254
|
+
outputPath: resolve(config.root, config.output.path),
|
|
255
|
+
files,
|
|
256
|
+
barrelType
|
|
200
257
|
});
|
|
201
|
-
if (relevantFiles.length === 0) return [];
|
|
202
|
-
const tree = buildTree(outputPath, relevantFiles.map((f) => f.path));
|
|
203
|
-
switch (barrelType) {
|
|
204
|
-
case "all": return getBarrelFilesAll(tree, relevantFiles);
|
|
205
|
-
case "named": return getBarrelFilesNamed(tree, relevantFiles);
|
|
206
|
-
case "propagate": return getBarrelFilesPropagate(tree);
|
|
207
|
-
default: return [];
|
|
208
|
-
}
|
|
209
258
|
}
|
|
210
259
|
//#endregion
|
|
211
|
-
//#region src/utils/
|
|
260
|
+
//#region src/utils/excludedPaths.ts
|
|
212
261
|
/**
|
|
213
|
-
*
|
|
262
|
+
* Returns the absolute output directory of `plugin` with a trailing separator,
|
|
263
|
+
* suitable for prefix-based exclusion checks via {@link isExcludedPath}.
|
|
214
264
|
*
|
|
215
|
-
* The
|
|
216
|
-
*
|
|
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}).
|
|
217
274
|
*
|
|
218
|
-
*
|
|
219
|
-
* Files generated by plugins land at `config.root + config.output.path + plugin.output.path`,
|
|
220
|
-
* so the barrel directory must be resolved with all three segments.
|
|
275
|
+
* Uses Node 22 iterator helpers (`Iterator.prototype.some`) to avoid materializing the set.
|
|
221
276
|
*/
|
|
222
|
-
function
|
|
223
|
-
return
|
|
277
|
+
function isExcludedPath(filePath, prefixes) {
|
|
278
|
+
return prefixes.values().some((prefix) => filePath.startsWith(prefix));
|
|
224
279
|
}
|
|
225
280
|
//#endregion
|
|
226
|
-
//#region src/utils/
|
|
281
|
+
//#region src/utils/resolveBarrelType.ts
|
|
282
|
+
const DEFAULT_BARREL_TYPE = "named";
|
|
227
283
|
/**
|
|
228
|
-
*
|
|
229
|
-
*
|
|
230
|
-
* The root barrel re-exports from all files across all plugins that are located
|
|
231
|
-
* inside the root output directory, using the given `barrelType` strategy.
|
|
232
|
-
*
|
|
233
|
-
* In practice this re-exports the per-plugin barrels when `barrelType = 'propagate'`,
|
|
234
|
-
* or all individual files when `barrelType = 'all'` or `'named'`.
|
|
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.
|
|
235
286
|
*/
|
|
236
|
-
function
|
|
237
|
-
return
|
|
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;
|
|
238
296
|
}
|
|
239
297
|
//#endregion
|
|
240
298
|
//#region src/middleware.ts
|
|
241
299
|
/**
|
|
242
|
-
*
|
|
243
|
-
*
|
|
244
|
-
* When added to `config.middleware`, generates an `index.ts` barrel file for each
|
|
245
|
-
* plugin. When `output.barrelType` is omitted on a plugin it inherits from `config.output.barrelType`,
|
|
246
|
-
* and when that is also omitted both default to `'all'`. Set `barrelType: false` to disable
|
|
247
|
-
* barrel generation for a specific plugin or for the root entirely.
|
|
300
|
+
* Generates `index.ts` barrel files for each plugin's output directory and one root barrel
|
|
301
|
+
* at `config.output.path/index.ts`.
|
|
248
302
|
*
|
|
249
|
-
*
|
|
250
|
-
*
|
|
251
|
-
*
|
|
252
|
-
* - `'propagate'` — like `'all'` with intermediate barrel files for sub-directories
|
|
303
|
+
* Plugins inherit `output.barrelType` from `config.output.barrelType` (which itself defaults to `'named'`).
|
|
304
|
+
* Setting `barrelType: false` on a plugin disables its barrel and excludes the plugin's files from the
|
|
305
|
+
* root barrel as well.
|
|
253
306
|
*
|
|
254
307
|
* @example
|
|
255
308
|
* ```ts
|
|
309
|
+
* import { defineConfig } from '@kubb/core'
|
|
256
310
|
* import { middlewareBarrel } from '@kubb/middleware-barrel'
|
|
257
311
|
*
|
|
258
312
|
* export default defineConfig({
|
|
@@ -269,15 +323,15 @@ const middlewareBarrel = defineMiddleware({
|
|
|
269
323
|
name: "middleware-barrel",
|
|
270
324
|
install(hooks) {
|
|
271
325
|
let ctx;
|
|
272
|
-
const
|
|
326
|
+
const excludedPrefixes = /* @__PURE__ */ new Set();
|
|
273
327
|
hooks.on("kubb:build:start", (buildCtx) => {
|
|
274
328
|
ctx = buildCtx;
|
|
275
329
|
});
|
|
276
330
|
hooks.on("kubb:plugin:end", ({ plugin }) => {
|
|
277
331
|
if (!ctx) return;
|
|
278
|
-
const barrelType = plugin
|
|
332
|
+
const barrelType = resolvePluginBarrelType(plugin, ctx.config);
|
|
279
333
|
if (!barrelType) {
|
|
280
|
-
|
|
334
|
+
excludedPrefixes.add(getPluginOutputPrefix(plugin, ctx.config));
|
|
281
335
|
return;
|
|
282
336
|
}
|
|
283
337
|
const barrelFiles = generatePerPluginBarrel({
|
|
@@ -289,11 +343,11 @@ const middlewareBarrel = defineMiddleware({
|
|
|
289
343
|
if (barrelFiles.length > 0) ctx.upsertFile(...barrelFiles);
|
|
290
344
|
});
|
|
291
345
|
hooks.on("kubb:plugins:end", ({ files, config, upsertFile }) => {
|
|
292
|
-
const rootBarrelType = config
|
|
346
|
+
const rootBarrelType = resolveRootBarrelType(config);
|
|
293
347
|
if (!rootBarrelType) return;
|
|
294
348
|
const rootBarrelFiles = generateRootBarrel({
|
|
295
349
|
barrelType: rootBarrelType,
|
|
296
|
-
files:
|
|
350
|
+
files: excludedPrefixes.size === 0 ? files : files.filter((f) => !isExcludedPath(f.path, excludedPrefixes)),
|
|
297
351
|
config
|
|
298
352
|
});
|
|
299
353
|
if (rootBarrelFiles.length > 0) upsertFile(...rootBarrelFiles);
|