@kubb/plugin-barrel 5.8.0 → 5.8.1

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/OVERVIEW.md ADDED
@@ -0,0 +1,30 @@
1
+ # Barrel plugin
2
+
3
+ The barrel plugin writes `index.ts` files that re-export generated code, one for each plugin's output and one root barrel, so you can import everything from a single entry point.
4
+
5
+ Kubb adds it to `plugins` for you. Do not add it yourself. It generates nothing until you configure `output.barrel`.
6
+
7
+ ## Setup
8
+
9
+ Set `output.barrel` on `defineConfig` to write a root barrel. Plugins without a barrel setting of their own inherit it.
10
+
11
+ ```ts
12
+ import { defineConfig } from 'kubb/config'
13
+ import { pluginTs } from '@kubb/plugin-ts'
14
+
15
+ export default defineConfig({
16
+ input: './petStore.yaml',
17
+ output: { path: './src/gen', barrel: { type: 'named' } },
18
+ plugins: [pluginTs()],
19
+ })
20
+ ```
21
+
22
+ ## Options
23
+
24
+ The plugin takes no arguments. You configure it through `output.barrel`, on `defineConfig` or on a single plugin.
25
+
26
+ - `type: 'named'` re-exports each symbol by name, which suits tree-shaking. `type: 'all'` writes `export *`.
27
+ - `nested: true`, on a plugin only, makes each barrel re-export just its own directory and the barrels below it. The root barrel is always flat.
28
+ - `false` on a plugin turns its barrel off and leaves its files out of the root barrel.
29
+
30
+ A plugin with `output.mode: 'file'` gets no barrel of its own. The root barrel re-exports that file directly. Passing your own `output` object to a plugin replaces its default `barrel: { type: 'named' }`, so it falls back to the root setting.
package/dist/index.cjs CHANGED
@@ -64,6 +64,15 @@ function isPathInside(path, parent) {
64
64
  return rel !== "" && !rel.startsWith("..") && !(0, node_path.isAbsolute)(rel);
65
65
  }
66
66
  //#endregion
67
+ //#region kubb-extension.json
68
+ var compatibility = {
69
+ "kubb": ">=5.8.0",
70
+ "node": ">=22"
71
+ };
72
+ //#endregion
73
+ //#region package.json
74
+ var version = "5.8.1";
75
+ //#endregion
67
76
  //#region src/utils.ts
68
77
  const SOURCE_EXTENSIONS = /* @__PURE__ */ new Set([
69
78
  ".ts",
@@ -73,219 +82,124 @@ const SOURCE_EXTENSIONS = /* @__PURE__ */ new Set([
73
82
  ]);
74
83
  const BARREL_SUFFIX = `/index.ts`;
75
84
  /**
76
- * Builds a directory tree rooted at `rootPath` from a list of absolute file paths.
77
- * Paths outside `rootPath` are silently ignored. Children are sorted alphabetically
78
- * by path so consumers (barrel exports, propagated indexes) emit a deterministic order.
79
- *
80
- * Both POSIX (`/`) and Windows (`\`) separators are accepted in input paths; emitted node
81
- * paths are always POSIX-normalized so downstream prefix/lookup operations behave the same
82
- * across platforms.
83
- *
84
- * @example
85
- * ```ts
86
- * buildTree('/src/gen/types', [
87
- * '/src/gen/types/pet.ts',
88
- * '/src/gen/types/pets/listPets.ts',
89
- * ])
90
- * ```
85
+ * Orders paths split into segments the way a directory listing sorts them: by name at each level.
91
86
  */
92
- function buildTree(rootPath, filePaths) {
93
- const normalizedRoot = toPosixPath(rootPath);
94
- const root = {
95
- path: normalizedRoot,
96
- children: [],
97
- isFile: false
98
- };
99
- const childIndex = /* @__PURE__ */ new WeakMap();
100
- childIndex.set(root, /* @__PURE__ */ new Map());
101
- const rootPrefix = `${normalizedRoot}/`;
102
- for (const filePath of filePaths) {
103
- const normalized = toPosixPath(filePath);
104
- if (!normalized.startsWith(rootPrefix)) continue;
105
- const parts = normalized.slice(rootPrefix.length).split("/");
106
- let current = root;
107
- const lastIndex = parts.length - 1;
108
- for (const [i, part] of parts.entries()) {
109
- if (!part) continue;
110
- const isLast = i === lastIndex;
111
- const siblings = childIndex.get(current);
112
- let child = siblings.get(part);
113
- if (!child) {
114
- child = {
115
- path: `${current.path}/${part}`,
116
- children: [],
117
- isFile: isLast
118
- };
119
- current.children.push(child);
120
- siblings.set(part, child);
121
- if (!isLast) childIndex.set(child, /* @__PURE__ */ new Map());
122
- }
123
- current = child;
124
- }
125
- }
126
- sortTree(root);
127
- return root;
87
+ function compareSegments(a, b) {
88
+ const index = a.findIndex((segment, i) => segment !== b[i]);
89
+ if (index === -1) return a.length - b.length;
90
+ if (index >= b.length) return 1;
91
+ return a[index] < b[index] ? -1 : 1;
128
92
  }
129
- function sortTree(node) {
130
- if (node.children.length === 0) return;
131
- node.children.sort(compareByPath);
132
- for (const child of node.children) if (!child.isFile) sortTree(child);
133
- }
134
- function compareByPath(a, b) {
135
- return a.path < b.path ? -1 : a.path > b.path ? 1 : 0;
136
- }
137
- function toRelativeModulePath({ fromDir, filePath }) {
93
+ function toRelativeModulePath(fromDir, filePath) {
138
94
  return `./${node_path.posix.relative(fromDir, filePath)}`;
139
95
  }
140
- function isBarrelPath(path) {
141
- return path.endsWith(BARREL_SUFFIX);
142
- }
143
- function makeBarrel({ dirPath, exports, sourceFiles, reportedCollisions }) {
144
- const names = /* @__PURE__ */ new Map();
145
- const uniqueExports = [];
146
- for (const item of exports) {
96
+ /**
97
+ * Builds the `index.ts` for `dirPath`. Keeps the first export of each name and reports later duplicates once per build.
98
+ */
99
+ function makeBarrel(dirPath, exports, { sourceFiles, reportedCollisions }) {
100
+ const owners = /* @__PURE__ */ new Map();
101
+ const uniqueExports = exports.flatMap((item) => {
147
102
  const itemPath = node_path.posix.join(dirPath, item.path);
148
- const itemNames = Array.isArray(item.name) ? item.name : item.name ? [item.name] : sourceFiles.get(itemPath)?.sources.flatMap((source) => source.name ? [source.name] : []);
149
- const uniqueNames = [];
150
- for (const name of itemNames ?? []) {
151
- const first = names.get(name);
103
+ const uniqueNames = (item.name == null ? sourceFiles.get(itemPath)?.sources.flatMap((source) => source.name || []) ?? [] : [item.name].flat()).filter((name) => {
104
+ const first = owners.get(name);
152
105
  if (!first) {
153
- names.set(name, item.path);
154
- uniqueNames.push(name);
155
- continue;
106
+ owners.set(name, item.path);
107
+ return true;
156
108
  }
157
109
  const key = [
158
110
  name,
159
111
  node_path.posix.join(dirPath, first),
160
112
  itemPath
161
113
  ].join("\0");
162
- if (reportedCollisions.has(key)) continue;
163
- reportedCollisions.add(key);
164
- _kubb_kit.Diagnostics.report({
165
- code: _kubb_kit.Diagnostics.code.barrelDuplicateExport,
166
- severity: "error",
167
- message: `"${name}" is exported by both "${first}" and "${item.path}", so "${dirPath}${BARREL_SUFFIX}" cannot re-export both.`,
168
- help: "Rename one of the colliding declarations, or configure the plugin resolver to produce distinct names."
169
- });
170
- }
171
- if (!itemNames || item.name == null || uniqueNames.length > 0) uniqueExports.push(item.name == null ? item : _kubb_kit.ast.factory.createExport({
114
+ if (!reportedCollisions.has(key)) {
115
+ reportedCollisions.add(key);
116
+ _kubb_kit.Diagnostics.report({
117
+ code: _kubb_kit.Diagnostics.code.barrelDuplicateExport,
118
+ severity: "error",
119
+ message: `"${name}" is exported by both "${first}" and "${item.path}", so "${dirPath}${BARREL_SUFFIX}" cannot re-export both.`,
120
+ help: "Rename one of the colliding declarations, or configure the plugin resolver to produce distinct names."
121
+ });
122
+ }
123
+ return false;
124
+ });
125
+ if (item.name == null) return [item];
126
+ return uniqueNames.length > 0 ? [_kubb_kit.ast.factory.createExport({
172
127
  ...item,
173
128
  name: Array.isArray(item.name) ? uniqueNames : uniqueNames[0]
174
- }));
175
- }
129
+ })] : [];
130
+ });
176
131
  return _kubb_kit.ast.factory.createFile({
177
132
  baseName: "index.ts",
178
133
  path: `${dirPath}${BARREL_SUFFIX}`,
179
134
  exports: uniqueExports
180
135
  });
181
136
  }
182
- function indexableNames({ sources, isTypeOnly }) {
137
+ function indexableNames(sources, isTypeOnly) {
183
138
  const names = sources.flatMap((source) => source.isIndexable && source.name && Boolean(source.isTypeOnly) === isTypeOnly ? [source.name] : []);
184
139
  return [...new Set(names)].sort();
185
140
  }
186
- const allStrategy = ({ dirPath, leafPath, sourceFile }) => {
141
+ /**
142
+ * Re-exports the whole module, unless it has sources and none of them is indexable.
143
+ */
144
+ const allStrategy = (path, sourceFile) => {
187
145
  const sources = sourceFile?.sources ?? [];
188
- if (sources.length > 0 && !sources.some((source) => source.isIndexable)) return [];
189
- return [_kubb_kit.ast.factory.createExport({ path: toRelativeModulePath({
190
- fromDir: dirPath,
191
- filePath: leafPath
192
- }) })];
146
+ return sources.length > 0 && !sources.some((source) => source.isIndexable) ? [] : [_kubb_kit.ast.factory.createExport({ path })];
193
147
  };
194
- const namedStrategy = ({ dirPath, leafPath, sourceFile }) => {
195
- const modulePath = toRelativeModulePath({
196
- fromDir: dirPath,
197
- filePath: leafPath
198
- });
199
- if (!sourceFile) return [_kubb_kit.ast.factory.createExport({ path: modulePath })];
200
- const valueNames = indexableNames({
201
- sources: sourceFile.sources,
202
- isTypeOnly: false
203
- });
204
- const typeNames = indexableNames({
205
- sources: sourceFile.sources,
206
- isTypeOnly: true
207
- });
208
- if (valueNames.length === 0 && typeNames.length === 0) {
209
- if (sourceFile.sources.length > 0) return [];
210
- return [_kubb_kit.ast.factory.createExport({ path: modulePath })];
211
- }
212
- const exports = [];
213
- if (valueNames.length > 0) exports.push(_kubb_kit.ast.factory.createExport({
148
+ /**
149
+ * Re-exports the indexable names, values and types separately, or the whole module when it has no sources.
150
+ */
151
+ const namedStrategy = (path, sourceFile) => {
152
+ if (!sourceFile?.sources.length) return [_kubb_kit.ast.factory.createExport({ path })];
153
+ const valueNames = indexableNames(sourceFile.sources, false);
154
+ const typeNames = indexableNames(sourceFile.sources, true);
155
+ return [...valueNames.length > 0 ? [_kubb_kit.ast.factory.createExport({
214
156
  name: valueNames,
215
- path: modulePath
216
- }));
217
- if (typeNames.length > 0) exports.push(_kubb_kit.ast.factory.createExport({
157
+ path
158
+ })] : [], ...typeNames.length > 0 ? [_kubb_kit.ast.factory.createExport({
218
159
  name: typeNames,
219
- path: modulePath,
160
+ path,
220
161
  isTypeOnly: true
221
- }));
222
- return exports;
162
+ })] : []];
223
163
  };
224
164
  /**
225
- * Post-order walk that yields a barrel per visited directory.
226
- * Returns the list of leaf file paths collected in this subtree (used by the parent call).
165
+ * Post-order walk that builds a barrel re-exporting every leaf below the visited directory, for
166
+ * the start node and, with `recursive`, every sub-directory. Also returns the subtree's leaf paths.
227
167
  */
228
- function* walkAllOrNamed(node, params, { isRoot, recursive }) {
229
- const subtreeLeaves = [];
230
- for (const child of node.children) {
231
- if (child.isFile) {
232
- if (!isBarrelPath(child.path)) subtreeLeaves.push(child.path);
233
- continue;
234
- }
235
- const childLeaves = yield* walkAllOrNamed(child, params, {
236
- isRoot: false,
237
- recursive
238
- });
239
- for (const leaf of childLeaves) subtreeLeaves.push(leaf);
240
- }
241
- if (!isRoot && !recursive) return subtreeLeaves;
242
- const exports = subtreeLeaves.flatMap((leafPath) => params.strategy({
243
- dirPath: node.path,
244
- leafPath,
245
- sourceFile: params.sourceFiles.get(leafPath)
246
- }));
247
- if (exports.length > 0) yield makeBarrel({
248
- dirPath: node.path,
249
- exports,
250
- sourceFiles: params.sourceFiles,
251
- reportedCollisions: params.reportedCollisions
168
+ function walkFlat(node, ctx, isRoot = true) {
169
+ const results = [...node.children.values()].map((child) => child.children ? walkFlat(child, ctx, false) : {
170
+ barrels: [],
171
+ leaves: [child.path]
252
172
  });
253
- return subtreeLeaves;
173
+ const barrels = results.flatMap((result) => result.barrels);
174
+ const leaves = results.flatMap((result) => result.leaves);
175
+ const exports = isRoot || ctx.recursive ? leaves.flatMap((leaf) => ctx.leafExports(node.path, leaf)) : [];
176
+ return {
177
+ barrels: exports.length > 0 ? [...barrels, makeBarrel(node.path, exports, ctx)] : barrels,
178
+ leaves
179
+ };
254
180
  }
255
181
  /**
256
- * Recursive walk that yields one barrel per directory, re-exporting files and sub-barrels.
182
+ * Recursive walk that builds one barrel per directory, re-exporting files and sub-barrels.
257
183
  * Used when nested: true. Leaf files honor the barrel `strategy`, so `named` emits explicit
258
184
  * named exports instead of wildcards. Sub-directory barrels are chained with a wildcard
259
- * re-export, which forwards the names the child barrel already curated. Returns whether this
260
- * node yielded a barrel, so a parent never re-exports a sub-directory that produced nothing.
185
+ * re-export, which forwards the names the child barrel already curated. A sub-directory that
186
+ * produced no barrel is never re-exported.
261
187
  */
262
- function* walkNested(node, params) {
263
- const exports = [];
264
- for (const child of node.children) {
265
- if (child.isFile) {
266
- if (isBarrelPath(child.path)) continue;
267
- exports.push(...params.strategy({
268
- dirPath: node.path,
269
- leafPath: child.path,
270
- sourceFile: params.sourceFiles.get(child.path)
271
- }));
272
- continue;
273
- }
274
- if (yield* walkNested(child, params)) exports.push(_kubb_kit.ast.factory.createExport({ path: toRelativeModulePath({
275
- fromDir: node.path,
276
- filePath: `${child.path}${BARREL_SUFFIX}`
277
- }) }));
278
- }
279
- if (exports.length > 0) {
280
- yield makeBarrel({
281
- dirPath: node.path,
282
- exports,
283
- sourceFiles: params.sourceFiles,
284
- reportedCollisions: params.reportedCollisions
285
- });
286
- return true;
287
- }
288
- return false;
188
+ function walkNested(node, ctx) {
189
+ const results = [...node.children.values()].map((child) => {
190
+ if (!child.children) return {
191
+ barrels: [],
192
+ exports: ctx.leafExports(node.path, child.path)
193
+ };
194
+ const barrels = walkNested(child, ctx);
195
+ return {
196
+ barrels,
197
+ exports: barrels.length > 0 ? [_kubb_kit.ast.factory.createExport({ path: toRelativeModulePath(node.path, `${child.path}${BARREL_SUFFIX}`) })] : []
198
+ };
199
+ });
200
+ const barrels = results.flatMap((result) => result.barrels);
201
+ const exports = results.flatMap((result) => result.exports);
202
+ return exports.length > 0 ? [...barrels, makeBarrel(node.path, exports, ctx)] : barrels;
289
203
  }
290
204
  /**
291
205
  * Indexes `files` once for the directory rooted at `outputPath`: filters to indexable source
@@ -293,62 +207,62 @@ function* walkNested(node, params) {
293
207
  * derived from the same root rather than re-filtering and re-building per barrel.
294
208
  */
295
209
  function buildBarrelIndex(outputPath, files) {
296
- const outputPrefix = `${toPosixPath(outputPath)}/`;
297
- const sourceFiles = /* @__PURE__ */ new Map();
298
- for (const file of files) {
299
- const normalized = toPosixPath(file.path);
300
- if (!normalized.startsWith(outputPrefix)) continue;
301
- if (isBarrelPath(normalized)) continue;
302
- if (!SOURCE_EXTENSIONS.has((0, node_path.extname)(normalized))) continue;
303
- sourceFiles.set(normalized, file);
304
- }
210
+ const tree = {
211
+ path: toPosixPath(outputPath),
212
+ children: /* @__PURE__ */ new Map()
213
+ };
214
+ const sourceFiles = new Map(files.flatMap((file) => {
215
+ const filePath = toPosixPath(file.path);
216
+ return filePath.startsWith(`${tree.path}/`) && !filePath.endsWith(BARREL_SUFFIX) && SOURCE_EXTENSIONS.has((0, node_path.extname)(filePath)) ? [[filePath, file]] : [];
217
+ }));
218
+ [...sourceFiles.keys()].map((filePath) => filePath.slice(tree.path.length + 1).split("/").filter(Boolean)).sort(compareSegments).forEach((parts) => {
219
+ parts.reduce((dir, part, i) => {
220
+ const path = `${dir.path}/${part}`;
221
+ const child = dir.children.get(part) ?? (i === parts.length - 1 ? { path } : {
222
+ path,
223
+ children: /* @__PURE__ */ new Map()
224
+ });
225
+ dir.children.set(part, child);
226
+ return child.children ? child : dir;
227
+ }, tree);
228
+ });
305
229
  return {
306
- tree: buildTree(outputPath, [...sourceFiles.keys()]),
230
+ tree,
307
231
  sourceFiles
308
232
  };
309
233
  }
310
234
  /**
311
- * Locates the node for `targetPath` within an index tree, walking down through directory nodes
312
- * only. Returns `undefined` when no file exists at or under `targetPath` (nothing to barrel).
235
+ * Locates the directory node for `targetPath` within an index tree. Returns `undefined` when no
236
+ * file exists under `targetPath` (nothing to barrel).
313
237
  */
314
- function findNode(node, targetPath) {
315
- if (node.path === targetPath) return node;
316
- if (node.isFile || !targetPath.startsWith(`${node.path}/`)) return void 0;
317
- for (const child of node.children) if (!child.isFile && (child.path === targetPath || targetPath.startsWith(`${child.path}/`))) return findNode(child, targetPath);
238
+ function findDirectory(tree, targetPath) {
239
+ if (targetPath === tree.path) return tree;
240
+ if (!targetPath.startsWith(`${tree.path}/`)) return void 0;
241
+ const node = targetPath.slice(tree.path.length + 1).split("/").reduce((current, part) => current?.children?.get(part), tree);
242
+ return node?.children ? node : void 0;
318
243
  }
319
244
  /**
320
- * Yields barrel `ast.FileNode`s for `targetPath` (or the index root), derived from a shared index.
245
+ * Returns the barrel `ast.FileNode`s for `targetPath` (or the index root), derived from a shared index.
321
246
  * Locating the subtree is a bounded walk down from the root, so deriving many barrels (one per
322
247
  * plugin, plus the root) from one index avoids re-scanning the full file set for each.
323
248
  *
324
249
  * @example
325
250
  * ```ts
326
251
  * const index = buildBarrelIndex(outputPath, files)
327
- * for (const file of getBarrelFiles({ index, targetPath, barrelType })) {
328
- * upsertFile(file)
329
- * }
252
+ * getBarrelFiles({ index, targetPath, barrelType }).forEach((file) => upsertFile(file))
330
253
  * ```
331
254
  */
332
- function* getBarrelFiles({ index, targetPath, barrelType, nested = false, recursive = false, reportedCollisions = /* @__PURE__ */ new Set() }) {
333
- const node = targetPath ? findNode(index.tree, toPosixPath(targetPath)) : index.tree;
334
- if (!node) return;
255
+ function getBarrelFiles({ index, targetPath, barrelType, nested = false, recursive = false, reportedCollisions = /* @__PURE__ */ new Set() }) {
256
+ const node = targetPath ? findDirectory(index.tree, toPosixPath(targetPath)) : index.tree;
257
+ if (!node) return [];
335
258
  const strategy = barrelType === "named" ? namedStrategy : allStrategy;
336
- if (nested) {
337
- yield* walkNested(node, {
338
- sourceFiles: index.sourceFiles,
339
- strategy,
340
- reportedCollisions
341
- });
342
- return;
343
- }
344
- yield* walkAllOrNamed(node, {
259
+ const ctx = {
345
260
  sourceFiles: index.sourceFiles,
346
- strategy,
347
- reportedCollisions
348
- }, {
349
- isRoot: true,
350
- recursive
351
- });
261
+ reportedCollisions,
262
+ recursive,
263
+ leafExports: (dirPath, leafPath) => strategy(toRelativeModulePath(dirPath, leafPath), index.sourceFiles.get(leafPath))
264
+ };
265
+ return nested ? walkNested(node, ctx) : walkFlat(node, ctx).barrels;
352
266
  }
353
267
  //#endregion
354
268
  //#region src/plugin.ts
@@ -388,6 +302,7 @@ const pluginBarrelName = "plugin-barrel";
388
302
  const states = /* @__PURE__ */ new WeakMap();
389
303
  function getState(config) {
390
304
  const state = states.get(config) ?? {
305
+ excludedPlugins: /* @__PURE__ */ new Set(),
391
306
  excludedTargets: [],
392
307
  pendingBarrels: []
393
308
  };
@@ -428,19 +343,25 @@ function getState(config) {
428
343
  * ```
429
344
  */
430
345
  const pluginBarrel = (0, _kubb_kit.definePlugin)({
431
- meta: { name: pluginBarrelName },
346
+ meta: {
347
+ name: pluginBarrelName,
348
+ version,
349
+ compatibility
350
+ },
432
351
  enforce: "post",
433
352
  hooks: {
434
353
  "kubb:plugin:end"({ plugin, config }) {
435
354
  if (plugin.name === "plugin-barrel") return;
436
- const { excludedTargets, pendingBarrels } = getState(config);
355
+ const { excludedPlugins, excludedTargets, pendingBarrels } = getState(config);
437
356
  const barrelConfig = plugin.options.output?.barrel ?? config.output.barrel ?? false;
438
357
  const base = node_path.default.resolve(config.root, config.output.path);
439
- const target = node_path.default.resolve(base, plugin.options.output.path);
358
+ const target = node_path.default.resolve(base, plugin.options.output.path ?? ".");
440
359
  if (barrelConfig === false) {
441
- excludedTargets.push(target);
360
+ excludedPlugins.add(plugin.name);
361
+ if (target !== base && isPathInside(target, base)) excludedTargets.push(target);
442
362
  return;
443
363
  }
364
+ if (target === base) return;
444
365
  if (plugin.options.output.mode === "file") return;
445
366
  if (!isPathInside(target, base)) throw new _kubb_kit.Diagnostics.Error({
446
367
  code: _kubb_kit.Diagnostics.code.pathTraversal,
@@ -457,32 +378,43 @@ const pluginBarrel = (0, _kubb_kit.definePlugin)({
457
378
  });
458
379
  },
459
380
  "kubb:plugins:end"({ files, config, upsertFile }) {
460
- const { excludedTargets, pendingBarrels } = getState(config);
381
+ const { excludedPlugins, excludedTargets, pendingBarrels } = getState(config);
461
382
  const rootBarrelConfig = config.output.barrel ?? false;
462
383
  const outputPath = node_path.default.resolve(config.root, config.output.path);
463
- const relevantFiles = files.filter((file) => !excludedTargets.some((target) => isPathInside(file.path, target)));
384
+ const relevantFiles = files.filter((file) => {
385
+ const owner = file.meta?.pluginName;
386
+ if (owner) return !excludedPlugins.has(owner);
387
+ return !excludedTargets.some((target) => isPathInside(file.path, target));
388
+ });
389
+ excludedPlugins.clear();
464
390
  excludedTargets.length = 0;
465
391
  const index = buildBarrelIndex(outputPath, relevantFiles);
466
392
  const reportedCollisions = /* @__PURE__ */ new Set();
467
- for (const { plugin, target, barrelType, nested } of pendingBarrels) for (const file of getBarrelFiles({
468
- index,
469
- targetPath: target,
470
- barrelType,
471
- nested,
472
- recursive: true,
473
- reportedCollisions
474
- })) upsertFile(withBarrelBannerFooter({
475
- file,
476
- plugin,
477
- config
478
- }));
393
+ pendingBarrels.forEach(({ plugin, target, barrelType, nested }) => {
394
+ getBarrelFiles({
395
+ index,
396
+ targetPath: target,
397
+ barrelType,
398
+ nested,
399
+ recursive: true,
400
+ reportedCollisions
401
+ }).forEach((file) => {
402
+ upsertFile(withBarrelBannerFooter({
403
+ file,
404
+ plugin,
405
+ config
406
+ }));
407
+ });
408
+ });
479
409
  pendingBarrels.length = 0;
480
410
  if (rootBarrelConfig === false) return;
481
- for (const file of getBarrelFiles({
411
+ getBarrelFiles({
482
412
  index,
483
413
  barrelType: rootBarrelConfig.type,
484
414
  reportedCollisions
485
- })) upsertFile(file);
415
+ }).forEach((file) => {
416
+ upsertFile(file);
417
+ });
486
418
  }
487
419
  }
488
420
  });