@kubb/middleware-barrel 5.0.0-alpha.62 → 5.0.0-alpha.63
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 +74 -79
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +19 -30
- package/dist/index.js +74 -79
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/constants.ts +0 -1
- package/src/middleware.ts +17 -30
- package/src/types.ts +5 -7
- package/src/utils/buildTree.ts +9 -13
- package/src/utils/generatePerPluginBarrel.ts +17 -7
- package/src/utils/generateRootBarrel.ts +14 -7
- package/src/utils/getBarrelFiles.ts +84 -62
|
@@ -7,81 +7,82 @@ import { buildTree, type BuildTree } from './buildTree.ts'
|
|
|
7
7
|
const SOURCE_EXTENSIONS = new Set(['.ts', '.tsx', '.js', '.jsx'])
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
|
-
* Derives a relative module specifier from
|
|
11
|
-
* The source extension is preserved so
|
|
12
|
-
* (e.g. `.ts` → `.js` for ESM output).
|
|
10
|
+
* Derives a relative module specifier from `filePath` relative to `fromDir`.
|
|
11
|
+
* The source extension is preserved so `@kubb/parser-ts` can apply its `extNames` mapping.
|
|
13
12
|
*
|
|
14
13
|
* @example
|
|
14
|
+
* ```ts
|
|
15
15
|
* toRelativeModulePath('/src/gen/types', '/src/gen/types/pet.ts') // './pet.ts'
|
|
16
16
|
* toRelativeModulePath('/src/gen/types', '/src/gen/types/tags/tag.ts') // './tags/tag.ts'
|
|
17
|
+
* ```
|
|
17
18
|
*/
|
|
18
19
|
function toRelativeModulePath(fromDir: string, filePath: string): string {
|
|
19
20
|
const relative = filePath.slice(fromDir.length).replace(/^[/\\]/g, '')
|
|
20
21
|
return `./${relative}`
|
|
21
22
|
}
|
|
22
23
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
function getBarrelFilesAll(treeNode: BuildTree, sourceFiles: ReadonlyArray<FileNode>): Array<FileNode> {
|
|
31
|
-
// Collect all source file paths under this node (excluding barrel files themselves)
|
|
24
|
+
type BarrelFilesParams = {
|
|
25
|
+
treeNode: BuildTree
|
|
26
|
+
sourceFiles: ReadonlyArray<FileNode>
|
|
27
|
+
recursive?: boolean
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function getBarrelFilesAll({ treeNode, sourceFiles, recursive = false }: BarrelFilesParams): Array<FileNode> {
|
|
32
31
|
const leafPaths = collectLeafPaths(treeNode).filter((p) => !p.endsWith(`/${BARREL_FILENAME}`))
|
|
33
32
|
|
|
34
33
|
if (leafPaths.length === 0) return []
|
|
35
34
|
|
|
36
|
-
const barrelPath = `${treeNode.path}/${BARREL_FILENAME}`
|
|
37
35
|
const exports: ReturnType<typeof createExport>[] = []
|
|
38
36
|
|
|
39
37
|
for (const filePath of leafPaths) {
|
|
40
38
|
const sourceFile = sourceFiles.find((f) => f.path === filePath)
|
|
41
|
-
// Skip files whose sources all have isIndexable: false (e.g. internal injected files)
|
|
42
39
|
if (sourceFile && sourceFile.sources.length > 0 && sourceFile.sources.every((s) => !s.isIndexable)) {
|
|
43
40
|
continue
|
|
44
41
|
}
|
|
45
42
|
exports.push(createExport({ path: toRelativeModulePath(treeNode.path, filePath) }))
|
|
46
43
|
}
|
|
47
44
|
|
|
48
|
-
|
|
45
|
+
const result: Array<FileNode> = []
|
|
46
|
+
|
|
47
|
+
if (recursive) {
|
|
48
|
+
for (const child of treeNode.children) {
|
|
49
|
+
if (!child.isFile) {
|
|
50
|
+
result.push(...getBarrelFilesAll({ treeNode: child, sourceFiles, recursive: true }))
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (exports.length === 0) return result
|
|
49
56
|
|
|
50
|
-
|
|
57
|
+
result.push(
|
|
51
58
|
createFile({
|
|
52
59
|
baseName: BARREL_FILENAME,
|
|
53
|
-
path:
|
|
60
|
+
path: `${treeNode.path}/${BARREL_FILENAME}`,
|
|
54
61
|
exports,
|
|
55
62
|
sources: [],
|
|
56
63
|
imports: [],
|
|
57
64
|
}),
|
|
58
|
-
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
return result
|
|
59
68
|
}
|
|
60
69
|
|
|
61
|
-
|
|
62
|
-
* Generates barrel `FileNode[]` for a given directory tree node using the `'named'` strategy:
|
|
63
|
-
* each indexable source in each leaf file gets an individual named `export { name } from '...'`.
|
|
64
|
-
*/
|
|
65
|
-
function getBarrelFilesNamed(treeNode: BuildTree, sourceFiles: ReadonlyArray<FileNode>): Array<FileNode> {
|
|
70
|
+
function getBarrelFilesNamed({ treeNode, sourceFiles, recursive = false }: BarrelFilesParams): Array<FileNode> {
|
|
66
71
|
const leafPaths = collectLeafPaths(treeNode).filter((p) => !p.endsWith(`/${BARREL_FILENAME}`))
|
|
67
72
|
|
|
68
73
|
if (leafPaths.length === 0) return []
|
|
69
74
|
|
|
70
|
-
const barrelPath = `${treeNode.path}/${BARREL_FILENAME}`
|
|
71
75
|
const exports: ReturnType<typeof createExport>[] = []
|
|
72
76
|
|
|
73
77
|
for (const filePath of leafPaths) {
|
|
74
78
|
const sourceFile = sourceFiles.find((f) => f.path === filePath)
|
|
75
79
|
if (!sourceFile) {
|
|
76
|
-
// Fall back to wildcard if the source file is not in our set
|
|
77
80
|
exports.push(createExport({ path: toRelativeModulePath(treeNode.path, filePath) }))
|
|
78
81
|
continue
|
|
79
82
|
}
|
|
80
83
|
|
|
81
84
|
const indexableSources = sourceFile.sources.filter((s) => s.isIndexable && s.name)
|
|
82
85
|
if (indexableSources.length === 0) {
|
|
83
|
-
// If the file has explicit sources but none are indexable, skip it entirely.
|
|
84
|
-
// Only fall back to wildcard when there are no sources at all (unknown exports).
|
|
85
86
|
if (sourceFile.sources.length > 0) continue
|
|
86
87
|
exports.push(createExport({ path: toRelativeModulePath(treeNode.path, filePath) }))
|
|
87
88
|
continue
|
|
@@ -99,27 +100,32 @@ function getBarrelFilesNamed(treeNode: BuildTree, sourceFiles: ReadonlyArray<Fil
|
|
|
99
100
|
}
|
|
100
101
|
}
|
|
101
102
|
|
|
102
|
-
|
|
103
|
+
const result: Array<FileNode> = []
|
|
103
104
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
105
|
+
if (recursive) {
|
|
106
|
+
for (const child of treeNode.children) {
|
|
107
|
+
if (!child.isFile) {
|
|
108
|
+
result.push(...getBarrelFilesNamed({ treeNode: child, sourceFiles, recursive: true }))
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (exports.length > 0) {
|
|
114
|
+
result.push(
|
|
115
|
+
createFile({
|
|
116
|
+
baseName: BARREL_FILENAME,
|
|
117
|
+
path: `${treeNode.path}/${BARREL_FILENAME}`,
|
|
118
|
+
exports,
|
|
119
|
+
sources: [],
|
|
120
|
+
imports: [],
|
|
121
|
+
}),
|
|
122
|
+
)
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return result
|
|
113
126
|
}
|
|
114
127
|
|
|
115
|
-
|
|
116
|
-
* Generates barrel `FileNode[]` for a given directory tree node using the `'propagate'` strategy:
|
|
117
|
-
* like `'all'` but also generates intermediate barrel files for every sub-directory, so that
|
|
118
|
-
* consumers can import from any depth.
|
|
119
|
-
*
|
|
120
|
-
* Leaf barrels export directly from their files; parent barrels export from their sub-barrel files.
|
|
121
|
-
*/
|
|
122
|
-
function getBarrelFilesPropagate(treeNode: BuildTree): Array<FileNode> {
|
|
128
|
+
function getBarrelFilesPropagate({ treeNode }: Pick<BarrelFilesParams, 'treeNode'>): Array<FileNode> {
|
|
123
129
|
return collectPropagatedBarrels(treeNode)
|
|
124
130
|
}
|
|
125
131
|
|
|
@@ -133,11 +139,9 @@ function collectPropagatedBarrels(node: BuildTree): Array<FileNode> {
|
|
|
133
139
|
barrelExports.push(createExport({ path: toRelativeModulePath(node.path, child.path) }))
|
|
134
140
|
}
|
|
135
141
|
} else {
|
|
136
|
-
// Recurse into sub-directory
|
|
137
142
|
const subBarrels = collectPropagatedBarrels(child)
|
|
138
143
|
result.push(...subBarrels)
|
|
139
144
|
|
|
140
|
-
// Export the sub-directory's barrel (not individual files)
|
|
141
145
|
const subBarrelPath = `${child.path}/${BARREL_FILENAME}`
|
|
142
146
|
barrelExports.push(createExport({ path: toRelativeModulePath(node.path, subBarrelPath) }))
|
|
143
147
|
}
|
|
@@ -158,26 +162,44 @@ function collectPropagatedBarrels(node: BuildTree): Array<FileNode> {
|
|
|
158
162
|
return result
|
|
159
163
|
}
|
|
160
164
|
|
|
161
|
-
/**
|
|
162
|
-
* Collects all leaf (file) paths within a tree node recursively.
|
|
163
|
-
*/
|
|
164
165
|
function collectLeafPaths(node: BuildTree): Array<string> {
|
|
165
166
|
if (node.isFile) return [node.path]
|
|
166
167
|
return node.children.flatMap((c) => collectLeafPaths(c))
|
|
167
168
|
}
|
|
168
169
|
|
|
170
|
+
export type GetBarrelFilesParams = {
|
|
171
|
+
/**
|
|
172
|
+
* Absolute path to the directory the barrel(s) should be rooted at.
|
|
173
|
+
* Files outside this directory are ignored.
|
|
174
|
+
*/
|
|
175
|
+
outputPath: string
|
|
176
|
+
/**
|
|
177
|
+
* Full set of generated files across all plugins.
|
|
178
|
+
* Used both to discover what to re-export and to read each file's indexable sources.
|
|
179
|
+
*/
|
|
180
|
+
files: ReadonlyArray<FileNode>
|
|
181
|
+
/**
|
|
182
|
+
* Re-export style used in the generated barrel(s).
|
|
183
|
+
*/
|
|
184
|
+
barrelType: BarrelType
|
|
185
|
+
/**
|
|
186
|
+
* When `true`, also generate a barrel for each sub-directory of `outputPath`.
|
|
187
|
+
* Used by per-plugin barrels so that grouped output (e.g. `petController/`) gets its own `index.ts`.
|
|
188
|
+
*
|
|
189
|
+
* Has no effect for `barrelType: 'propagate'`, which always recurses by design.
|
|
190
|
+
*
|
|
191
|
+
* @default false
|
|
192
|
+
*/
|
|
193
|
+
recursive?: boolean
|
|
194
|
+
}
|
|
195
|
+
|
|
169
196
|
/**
|
|
170
|
-
* Generates barrel `FileNode
|
|
171
|
-
* generated source `files`, using the specified `barrelType` strategy.
|
|
172
|
-
*
|
|
173
|
-
* Files not located inside `outputPath` are excluded automatically.
|
|
197
|
+
* Generates barrel `FileNode`s for the directory rooted at `outputPath`.
|
|
174
198
|
*
|
|
175
|
-
*
|
|
176
|
-
*
|
|
177
|
-
* @param barrelType Barrel generation strategy.
|
|
199
|
+
* Files outside `outputPath`, existing barrel files, and non-source extensions are filtered out
|
|
200
|
+
* before the tree is built.
|
|
178
201
|
*/
|
|
179
|
-
export function getBarrelFiles(outputPath
|
|
180
|
-
// Only include files that live inside this outputPath and have a recognised source extension
|
|
202
|
+
export function getBarrelFiles({ outputPath, files, barrelType, recursive = false }: GetBarrelFilesParams): Array<FileNode> {
|
|
181
203
|
const relevantFiles = files.filter((f) => {
|
|
182
204
|
const normalizedFilePath = f.path.replace(/\\/g, '/')
|
|
183
205
|
const normalizedOutputPath = outputPath.replace(/\\/g, '/')
|
|
@@ -197,11 +219,11 @@ export function getBarrelFiles(outputPath: string, files: ReadonlyArray<FileNode
|
|
|
197
219
|
|
|
198
220
|
switch (barrelType) {
|
|
199
221
|
case 'all':
|
|
200
|
-
return getBarrelFilesAll(tree, relevantFiles)
|
|
222
|
+
return getBarrelFilesAll({ treeNode: tree, sourceFiles: relevantFiles, recursive })
|
|
201
223
|
case 'named':
|
|
202
|
-
return getBarrelFilesNamed(tree, relevantFiles)
|
|
224
|
+
return getBarrelFilesNamed({ treeNode: tree, sourceFiles: relevantFiles, recursive })
|
|
203
225
|
case 'propagate':
|
|
204
|
-
return getBarrelFilesPropagate(tree)
|
|
226
|
+
return getBarrelFilesPropagate({ treeNode: tree })
|
|
205
227
|
default:
|
|
206
228
|
return []
|
|
207
229
|
}
|