@kubb/middleware-barrel 5.0.0-beta.5 → 5.0.0-beta.50
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/LICENSE +17 -10
- package/README.md +108 -0
- package/dist/index.cjs +115 -68
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +25 -15
- package/dist/index.js +116 -69
- package/dist/index.js.map +1 -1
- package/extension.yaml +36 -29
- package/package.json +9 -6
- package/src/middleware.ts +62 -40
- package/src/types.ts +6 -6
- package/src/{utils/getBarrelFiles.ts → utils.ts} +58 -27
- package/src/constants.ts +0 -4
- package/src/utils/excludedPaths.ts +0 -22
- /package/dist/{chunk--u3MIqq1.js → chunk-C0LytTxp.js} +0 -0
package/extension.yaml
CHANGED
|
@@ -2,7 +2,7 @@ $schema: https://kubb.dev/schemas/extension.json
|
|
|
2
2
|
kind: middleware
|
|
3
3
|
id: middleware-barrel
|
|
4
4
|
name: Barrel
|
|
5
|
-
description:
|
|
5
|
+
description: Generates `index.ts` re-export files for every plugin output and one root barrel. Ships with Kubb and is enabled by default.
|
|
6
6
|
category: output
|
|
7
7
|
type: official
|
|
8
8
|
npmPackage: '@kubb/middleware-barrel'
|
|
@@ -26,9 +26,9 @@ resources:
|
|
|
26
26
|
changelog: https://github.com/kubb-labs/kubb/blob/main/packages/middleware-barrel/CHANGELOG.md
|
|
27
27
|
featured: true
|
|
28
28
|
intro: |-
|
|
29
|
-
|
|
29
|
+
`@kubb/middleware-barrel` generates an `index.ts` for every plugin output directory and one root barrel at `output.path/index.ts` after the build completes. The result is a single import surface for every consumer — `import { Pet, usePetByIdQuery, petMock } from './gen'`.
|
|
30
30
|
|
|
31
|
-
|
|
31
|
+
The middleware ships with Kubb and is registered by default in `defineConfig`, so barrels appear out of the box with no extra configuration. When `middlewareBarrel` is part of `config.middleware`, `defineConfig` also applies a default `output.barrel` of `{ type: 'named' }`. Custom middleware lists that omit `middlewareBarrel` leave `barrel` untouched.
|
|
32
32
|
|
|
33
33
|
Plugins inherit `output.barrel` from `config.output.barrel` when their own value is omitted. Setting `barrel: false` on a plugin disables that plugin's barrel **and** excludes its files from the root barrel.
|
|
34
34
|
options:
|
|
@@ -37,18 +37,20 @@ options:
|
|
|
37
37
|
required: false
|
|
38
38
|
default: "{ type: 'named' }"
|
|
39
39
|
description: |-
|
|
40
|
-
Re-export style for
|
|
40
|
+
Re-export style used for every generated barrel file. Set via `output.barrel` in `defineConfig` (applies to all plugins and the root barrel) or per plugin via that plugin's own `output.barrel`. It is not an argument to the middleware itself.
|
|
41
41
|
|
|
42
42
|
At the config level:
|
|
43
|
-
- `{ type: 'all' }` — `export * from '...'` for every generated file
|
|
44
|
-
- `{ type: 'named' }` — `export { name1, name2 } from '...'` using each file's named exports
|
|
45
|
-
- `false` — disables barrel generation entirely
|
|
46
43
|
|
|
47
|
-
|
|
48
|
-
- `{ type: 'named'
|
|
49
|
-
- `false` — disables barrel generation
|
|
44
|
+
- `{ type: 'all' }` — `export * from '...'` for every generated file.
|
|
45
|
+
- `{ type: 'named' }` — `export { Foo, Bar } from '...'` using each file's named exports.
|
|
46
|
+
- `false` — disables barrel generation entirely.
|
|
50
47
|
|
|
51
|
-
|
|
48
|
+
At the plugin level you also get `nested`:
|
|
49
|
+
|
|
50
|
+
- `{ type: 'named', nested: true }` — generates a barrel for every subdirectory, re-exporting only direct children. Lets callers import from any depth.
|
|
51
|
+
- `false` — disables the plugin's barrel and removes its files from the root barrel.
|
|
52
|
+
|
|
53
|
+
The `{ type: 'named' }` default kicks in only when `middlewareBarrel` is part of `config.middleware`.
|
|
52
54
|
codeBlock:
|
|
53
55
|
lang: typescript
|
|
54
56
|
title: kubb.config.ts
|
|
@@ -58,12 +60,13 @@ options:
|
|
|
58
60
|
import { middlewareBarrel } from '@kubb/middleware-barrel'
|
|
59
61
|
|
|
60
62
|
export default defineConfig({
|
|
61
|
-
input: { path: './
|
|
63
|
+
input: { path: './petStore.yaml' },
|
|
62
64
|
output: { path: './src/gen', barrel: { type: 'named' } },
|
|
63
65
|
middleware: [middlewareBarrel()],
|
|
66
|
+
plugins: [],
|
|
64
67
|
})
|
|
65
68
|
examples:
|
|
66
|
-
- name: "
|
|
69
|
+
- name: "{ type: 'named' } (default)"
|
|
67
70
|
files:
|
|
68
71
|
- name: kubb.config.ts
|
|
69
72
|
lang: typescript
|
|
@@ -72,10 +75,11 @@ examples:
|
|
|
72
75
|
import { defineConfig } from 'kubb'
|
|
73
76
|
|
|
74
77
|
export default defineConfig({
|
|
75
|
-
input: { path: './
|
|
78
|
+
input: { path: './petStore.yaml' },
|
|
76
79
|
output: { path: './src/gen' },
|
|
80
|
+
plugins: [],
|
|
77
81
|
})
|
|
78
|
-
- name:
|
|
82
|
+
- name: Generated output
|
|
79
83
|
lang: typescript
|
|
80
84
|
twoslash: false
|
|
81
85
|
code: |-
|
|
@@ -92,7 +96,7 @@ examples:
|
|
|
92
96
|
|
|
93
97
|
// src/gen/api/types/index.ts
|
|
94
98
|
export { User } from './User'
|
|
95
|
-
- name: "
|
|
99
|
+
- name: "{ type: 'all' }"
|
|
96
100
|
files:
|
|
97
101
|
- name: kubb.config.ts
|
|
98
102
|
lang: typescript
|
|
@@ -101,10 +105,11 @@ examples:
|
|
|
101
105
|
import { defineConfig } from 'kubb'
|
|
102
106
|
|
|
103
107
|
export default defineConfig({
|
|
104
|
-
input: { path: './
|
|
108
|
+
input: { path: './petStore.yaml' },
|
|
105
109
|
output: { path: './src/gen', barrel: { type: 'all' } },
|
|
110
|
+
plugins: [],
|
|
106
111
|
})
|
|
107
|
-
- name:
|
|
112
|
+
- name: Generated output
|
|
108
113
|
lang: typescript
|
|
109
114
|
twoslash: false
|
|
110
115
|
code: |-
|
|
@@ -121,7 +126,7 @@ examples:
|
|
|
121
126
|
|
|
122
127
|
// src/gen/api/types/index.ts
|
|
123
128
|
export * from './User'
|
|
124
|
-
- name: "
|
|
129
|
+
- name: "{ type: 'named', nested: true }"
|
|
125
130
|
files:
|
|
126
131
|
- name: kubb.config.ts
|
|
127
132
|
lang: typescript
|
|
@@ -130,10 +135,11 @@ examples:
|
|
|
130
135
|
import { defineConfig } from 'kubb'
|
|
131
136
|
|
|
132
137
|
export default defineConfig({
|
|
133
|
-
input: { path: './
|
|
138
|
+
input: { path: './petStore.yaml' },
|
|
134
139
|
output: { path: './src/gen', barrel: { type: 'named', nested: true } },
|
|
140
|
+
plugins: [],
|
|
135
141
|
})
|
|
136
|
-
- name:
|
|
142
|
+
- name: Generated output (chained structure)
|
|
137
143
|
lang: typescript
|
|
138
144
|
twoslash: false
|
|
139
145
|
code: |-
|
|
@@ -148,7 +154,7 @@ examples:
|
|
|
148
154
|
|
|
149
155
|
// src/gen/api/types/index.ts (exports files)
|
|
150
156
|
export * from './User'
|
|
151
|
-
- name: Disable barrel for a single plugin
|
|
157
|
+
- name: Disable the barrel for a single plugin
|
|
152
158
|
files:
|
|
153
159
|
- name: kubb.config.ts
|
|
154
160
|
lang: typescript
|
|
@@ -158,17 +164,17 @@ examples:
|
|
|
158
164
|
import { pluginTs } from '@kubb/plugin-ts'
|
|
159
165
|
import { pluginZod } from '@kubb/plugin-zod'
|
|
160
166
|
|
|
161
|
-
// pluginZod opts out: no zod/index.ts is created
|
|
167
|
+
// pluginZod opts out: no zod/index.ts is created,
|
|
162
168
|
// and zod files are excluded from the root index.ts.
|
|
163
169
|
export default defineConfig({
|
|
164
|
-
input: { path: './
|
|
170
|
+
input: { path: './petStore.yaml' },
|
|
165
171
|
output: { path: './src/gen' },
|
|
166
172
|
plugins: [
|
|
167
173
|
pluginTs(),
|
|
168
174
|
pluginZod({ output: { barrel: false } }),
|
|
169
175
|
],
|
|
170
176
|
})
|
|
171
|
-
- name: Disable the root barrel
|
|
177
|
+
- name: Disable only the root barrel
|
|
172
178
|
files:
|
|
173
179
|
- name: kubb.config.ts
|
|
174
180
|
lang: typescript
|
|
@@ -177,15 +183,16 @@ examples:
|
|
|
177
183
|
import { defineConfig } from 'kubb'
|
|
178
184
|
|
|
179
185
|
// No root index.ts is generated, but each plugin
|
|
180
|
-
// still gets its own barrel using its inherited
|
|
186
|
+
// still gets its own barrel using its inherited config.
|
|
181
187
|
export default defineConfig({
|
|
182
|
-
input: { path: './
|
|
188
|
+
input: { path: './petStore.yaml' },
|
|
183
189
|
output: { path: './src/gen', barrel: false },
|
|
190
|
+
plugins: [],
|
|
184
191
|
})
|
|
185
192
|
notes:
|
|
186
193
|
- type: tip
|
|
187
194
|
body: |-
|
|
188
|
-
`middleware-barrel`
|
|
195
|
+
`middleware-barrel` ships with Kubb and is enabled automatically when no `middleware` option is provided. Install it explicitly only when customizing barrel behavior alongside other middlewares.
|
|
189
196
|
- type: note
|
|
190
197
|
body: |-
|
|
191
|
-
`output.barrel` is
|
|
198
|
+
`output.barrel` is auto-defaulted to `{ type: 'named' }` only when `middlewareBarrel` is part of `config.middleware`. With a custom middleware list that omits it, set `output.barrel` yourself if you still want a barrel.
|
package/package.json
CHANGED
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kubb/middleware-barrel",
|
|
3
|
-
"version": "5.0.0-beta.
|
|
4
|
-
"description": "Barrel-file
|
|
3
|
+
"version": "5.0.0-beta.50",
|
|
4
|
+
"description": "Barrel-file middleware for Kubb. Automatically generates index.ts re-export files per plugin output directory and an optional root barrel after all plugins complete.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"barrel",
|
|
7
|
-
"code-generator",
|
|
8
7
|
"codegen",
|
|
9
8
|
"kubb",
|
|
10
9
|
"middleware",
|
|
11
|
-
"openapi",
|
|
12
10
|
"typescript"
|
|
13
11
|
],
|
|
14
12
|
"license": "MIT",
|
|
@@ -44,21 +42,26 @@
|
|
|
44
42
|
"access": "public",
|
|
45
43
|
"registry": "https://registry.npmjs.org/"
|
|
46
44
|
},
|
|
45
|
+
"dependencies": {
|
|
46
|
+
"@kubb/ast": "5.0.0-beta.50",
|
|
47
|
+
"@kubb/core": "5.0.0-beta.50"
|
|
48
|
+
},
|
|
47
49
|
"devDependencies": {
|
|
48
50
|
"@internals/utils": "0.0.0"
|
|
49
51
|
},
|
|
50
52
|
"peerDependencies": {
|
|
51
|
-
"@kubb/core": "5.0.0-beta.
|
|
53
|
+
"@kubb/core": "5.0.0-beta.50"
|
|
52
54
|
},
|
|
53
55
|
"engines": {
|
|
54
56
|
"node": ">=22"
|
|
55
57
|
},
|
|
56
58
|
"scripts": {
|
|
57
59
|
"build": "tsdown",
|
|
58
|
-
"clean": "
|
|
60
|
+
"clean": "node -e \"require('node:fs').rmSync('./dist', {recursive:true,force:true})\"",
|
|
59
61
|
"lint": "oxlint .",
|
|
60
62
|
"lint:fix": "oxlint --fix .",
|
|
61
63
|
"release": "pnpm publish --no-git-check",
|
|
64
|
+
"release:stage": "pnpm stage publish --no-git-check",
|
|
62
65
|
"start": "tsdown --watch",
|
|
63
66
|
"test": "vitest --passWithNoTests",
|
|
64
67
|
"typecheck": "tsc -p ./tsconfig.json --noEmit --emitDeclarationOnly false"
|
package/src/middleware.ts
CHANGED
|
@@ -1,10 +1,34 @@
|
|
|
1
1
|
import path from 'node:path'
|
|
2
2
|
import { resolve } from 'node:path'
|
|
3
|
+
import type { FileNode } from '@kubb/ast'
|
|
3
4
|
import { defineMiddleware } from '@kubb/core'
|
|
4
|
-
import type { Middleware } from '@kubb/core'
|
|
5
|
+
import type { Config, Middleware, NormalizedPlugin } from '@kubb/core'
|
|
5
6
|
import type { BarrelConfig, PluginBarrelConfig } from './types.ts'
|
|
6
|
-
import { getPluginOutputPrefix, isExcludedPath } from './utils
|
|
7
|
-
|
|
7
|
+
import { getBarrelFiles, getPluginOutputPrefix, isExcludedPath } from './utils.ts'
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Applies a plugin's configured `output.banner`/`footer` to a barrel file, flagged as `isBarrel`.
|
|
11
|
+
*
|
|
12
|
+
* Resolves through the plugin's own resolver, and only when the plugin explicitly sets a
|
|
13
|
+
* banner/footer, so barrels stay banner-free by default and never inherit the implicit
|
|
14
|
+
* "Generated by Kubb" notice.
|
|
15
|
+
*/
|
|
16
|
+
function withBarrelBannerFooter({ file, plugin, config }: { file: FileNode; plugin: NormalizedPlugin; config: Config }): FileNode {
|
|
17
|
+
const output = plugin.options?.output
|
|
18
|
+
const resolver = plugin.resolver
|
|
19
|
+
if (!resolver) return file
|
|
20
|
+
|
|
21
|
+
const hasBanner = output?.banner !== undefined
|
|
22
|
+
const hasFooter = output?.footer !== undefined
|
|
23
|
+
if (!hasBanner && !hasFooter) return file
|
|
24
|
+
|
|
25
|
+
const context = { output, config, file: { path: file.path, baseName: file.baseName, isBarrel: true } }
|
|
26
|
+
return {
|
|
27
|
+
...file,
|
|
28
|
+
banner: hasBanner ? resolver.resolveBanner(undefined, context) : file.banner,
|
|
29
|
+
footer: hasFooter ? resolver.resolveFooter(undefined, context) : file.footer,
|
|
30
|
+
}
|
|
31
|
+
}
|
|
8
32
|
|
|
9
33
|
declare global {
|
|
10
34
|
namespace Kubb {
|
|
@@ -12,7 +36,7 @@ declare global {
|
|
|
12
36
|
output: {
|
|
13
37
|
/**
|
|
14
38
|
* Barrel configuration for this plugin's output.
|
|
15
|
-
* Set to `false` to disable barrel generation for this plugin entirely
|
|
39
|
+
* Set to `false` to disable barrel generation for this plugin entirely. Doing so also
|
|
16
40
|
* excludes the plugin's files from the root barrel.
|
|
17
41
|
*
|
|
18
42
|
* Falls back to `config.output.barrel` when omitted.
|
|
@@ -38,17 +62,32 @@ declare global {
|
|
|
38
62
|
}
|
|
39
63
|
|
|
40
64
|
/**
|
|
41
|
-
*
|
|
65
|
+
* Canonical middleware name for `@kubb/middleware-barrel`. Used for driver
|
|
66
|
+
* lookups.
|
|
67
|
+
*/
|
|
68
|
+
export const middlewareBarrelName = 'middleware-barrel' satisfies Middleware['name']
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Generates an `index.ts` for every plugin output directory and one root
|
|
72
|
+
* barrel at `config.output.path/index.ts` after the build completes. Ships
|
|
73
|
+
* with Kubb and is registered by default in `defineConfig`.
|
|
74
|
+
*
|
|
75
|
+
* Each plugin inherits `output.barrel` from `config.output.barrel` (which
|
|
76
|
+
* defaults to `{ type: 'named' }`). Set `barrel: false` on a plugin to skip
|
|
77
|
+
* its barrel and also exclude its files from the root barrel.
|
|
42
78
|
*
|
|
43
|
-
*
|
|
44
|
-
*
|
|
79
|
+
* A plugin with `output.mode: 'file'` gets no per-plugin barrel, since its output
|
|
80
|
+
* is a single file. The root barrel re-exports that file directly.
|
|
45
81
|
*
|
|
46
82
|
* @example
|
|
47
83
|
* ```ts
|
|
48
84
|
* import { defineConfig } from '@kubb/core'
|
|
49
85
|
* import { middlewareBarrel } from '@kubb/middleware-barrel'
|
|
86
|
+
* import { pluginTs } from '@kubb/plugin-ts'
|
|
87
|
+
* import { pluginZod } from '@kubb/plugin-zod'
|
|
50
88
|
*
|
|
51
89
|
* export default defineConfig({
|
|
90
|
+
* input: { path: './petStore.yaml' },
|
|
52
91
|
* output: { path: 'src/gen', barrel: { type: 'named' } },
|
|
53
92
|
* plugins: [
|
|
54
93
|
* pluginTs({ output: { path: 'types', barrel: { type: 'all' } } }),
|
|
@@ -58,12 +97,6 @@ declare global {
|
|
|
58
97
|
* })
|
|
59
98
|
* ```
|
|
60
99
|
*/
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* Stable string identifier for the barrel middleware.
|
|
64
|
-
*/
|
|
65
|
-
export const middlewareBarrelName = 'middleware-barrel' satisfies Middleware['name']
|
|
66
|
-
|
|
67
100
|
export const middlewareBarrel = defineMiddleware(() => {
|
|
68
101
|
const excludedPrefixes = new Set<string>()
|
|
69
102
|
|
|
@@ -75,21 +108,24 @@ export const middlewareBarrel = defineMiddleware(() => {
|
|
|
75
108
|
const configBarrel = config.output.barrel
|
|
76
109
|
const defaultBarrel = { type: 'named' } as const
|
|
77
110
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
} else {
|
|
85
|
-
barrelConfig = defaultBarrel
|
|
86
|
-
}
|
|
111
|
+
// Root config barrel doesn't have nested, so we add it
|
|
112
|
+
const barrelConfig: PluginBarrelConfig | false = (() => {
|
|
113
|
+
if (pluginBarrel !== undefined) return pluginBarrel
|
|
114
|
+
if (configBarrel !== undefined) return configBarrel === false ? false : { ...configBarrel, nested: false }
|
|
115
|
+
return defaultBarrel
|
|
116
|
+
})()
|
|
87
117
|
|
|
88
118
|
if (barrelConfig === false) {
|
|
89
119
|
excludedPrefixes.add(getPluginOutputPrefix(plugin, config))
|
|
90
120
|
return
|
|
91
121
|
}
|
|
92
122
|
|
|
123
|
+
// `mode: 'file'` writes a single file, so there is no directory to barrel. The root barrel
|
|
124
|
+
// re-exports that file as a direct leaf of `config.output.path`.
|
|
125
|
+
if (plugin.options.output.mode === 'file') {
|
|
126
|
+
return
|
|
127
|
+
}
|
|
128
|
+
|
|
93
129
|
const barrelType = barrelConfig.type
|
|
94
130
|
const nested = barrelConfig.nested ?? false
|
|
95
131
|
|
|
@@ -99,16 +135,8 @@ export const middlewareBarrel = defineMiddleware(() => {
|
|
|
99
135
|
if (relative.startsWith('..') || path.isAbsolute(relative)) {
|
|
100
136
|
throw new Error('Invalid output path')
|
|
101
137
|
}
|
|
102
|
-
const
|
|
103
|
-
|
|
104
|
-
files,
|
|
105
|
-
barrelType,
|
|
106
|
-
nested,
|
|
107
|
-
recursive: true,
|
|
108
|
-
})
|
|
109
|
-
|
|
110
|
-
if (barrelFiles.length > 0) {
|
|
111
|
-
upsertFile(...barrelFiles)
|
|
138
|
+
for (const file of getBarrelFiles({ outputPath: target, files, barrelType, nested, recursive: true })) {
|
|
139
|
+
upsertFile(withBarrelBannerFooter({ file, plugin, config }))
|
|
112
140
|
}
|
|
113
141
|
},
|
|
114
142
|
'kubb:plugins:end'({ files, config, upsertFile }) {
|
|
@@ -121,14 +149,8 @@ export const middlewareBarrel = defineMiddleware(() => {
|
|
|
121
149
|
|
|
122
150
|
const barrelType = barrelConfig.type
|
|
123
151
|
|
|
124
|
-
const
|
|
125
|
-
|
|
126
|
-
files: filteredFiles,
|
|
127
|
-
barrelType,
|
|
128
|
-
})
|
|
129
|
-
|
|
130
|
-
if (rootBarrelFiles.length > 0) {
|
|
131
|
-
upsertFile(...rootBarrelFiles)
|
|
152
|
+
for (const file of getBarrelFiles({ outputPath: resolve(config.root, config.output.path), files: filteredFiles, barrelType })) {
|
|
153
|
+
upsertFile(file)
|
|
132
154
|
}
|
|
133
155
|
},
|
|
134
156
|
},
|
package/src/types.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Barrel export strategy.
|
|
3
3
|
*
|
|
4
|
-
* - `'all'`
|
|
5
|
-
* - `'named'`
|
|
4
|
+
* - `'all'` generates `export * from '...'` for every file
|
|
5
|
+
* - `'named'` generates `export { name1, name2 } from '...'` using each file's named exports
|
|
6
6
|
*/
|
|
7
7
|
export type BarrelType = 'all' | 'named'
|
|
8
8
|
|
|
@@ -19,8 +19,8 @@ export type BarrelType = 'all' | 'named'
|
|
|
19
19
|
export type BarrelConfig = {
|
|
20
20
|
/**
|
|
21
21
|
* Export strategy for the root barrel file.
|
|
22
|
-
* - `'all'`
|
|
23
|
-
* - `'named'`
|
|
22
|
+
* - `'all'` wildcard exports: `export * from './file'`
|
|
23
|
+
* - `'named'` explicit exports: `export { x, y } from './file'`
|
|
24
24
|
*/
|
|
25
25
|
type: BarrelType
|
|
26
26
|
}
|
|
@@ -40,8 +40,8 @@ export type BarrelConfig = {
|
|
|
40
40
|
export type PluginBarrelConfig = {
|
|
41
41
|
/**
|
|
42
42
|
* Export strategy for the plugin's barrel files.
|
|
43
|
-
* - `'all'`
|
|
44
|
-
* - `'named'`
|
|
43
|
+
* - `'all'` wildcard exports: `export * from './file'`
|
|
44
|
+
* - `'named'` explicit exports: `export { x, y } from './file'`
|
|
45
45
|
*/
|
|
46
46
|
type: BarrelType
|
|
47
47
|
/**
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { extname } from 'node:path'
|
|
1
|
+
import { extname, resolve } from 'node:path'
|
|
2
2
|
import { createExport, createFile } from '@kubb/ast'
|
|
3
3
|
import type { ExportNode, FileNode, SourceNode } from '@kubb/ast'
|
|
4
|
-
import {
|
|
5
|
-
import type { BarrelType } from '../types.ts'
|
|
4
|
+
import type { Config, NormalizedPlugin } from '@kubb/core'
|
|
6
5
|
import { type BuildTree, buildTree, toPosixPath } from '@internals/utils'
|
|
6
|
+
import type { BarrelType } from './types.ts'
|
|
7
7
|
|
|
8
8
|
const SOURCE_EXTENSIONS = new Set(['.ts', '.tsx', '.js', '.jsx'])
|
|
9
|
-
const BARREL_SUFFIX =
|
|
9
|
+
const BARREL_SUFFIX = `/index.ts`
|
|
10
10
|
|
|
11
11
|
function toRelativeModulePath(fromDir: string, filePath: string): string {
|
|
12
12
|
return `./${filePath.slice(fromDir.length + 1)}`
|
|
@@ -18,13 +18,14 @@ function isBarrelPath(path: string): boolean {
|
|
|
18
18
|
|
|
19
19
|
function makeBarrel(dirPath: string, exports: Array<ExportNode>): FileNode {
|
|
20
20
|
return createFile({
|
|
21
|
-
baseName:
|
|
21
|
+
baseName: 'index.ts',
|
|
22
22
|
path: `${dirPath}${BARREL_SUFFIX}`,
|
|
23
23
|
exports,
|
|
24
24
|
sources: [],
|
|
25
25
|
imports: [],
|
|
26
|
-
//
|
|
27
|
-
//
|
|
26
|
+
// Default to no banner/footer. The middleware resolves a configured plugin
|
|
27
|
+
// banner/footer (with isBarrel: true) afterwards, so a `banner` function can
|
|
28
|
+
// decide per file whether a barrel should carry a directive like "use server".
|
|
28
29
|
banner: undefined,
|
|
29
30
|
footer: undefined,
|
|
30
31
|
})
|
|
@@ -33,7 +34,7 @@ function makeBarrel(dirPath: string, exports: Array<ExportNode>): FileNode {
|
|
|
33
34
|
type LeafContext = {
|
|
34
35
|
dirPath: string
|
|
35
36
|
leafPath: string
|
|
36
|
-
sourceFile: FileNode |
|
|
37
|
+
sourceFile: FileNode | null
|
|
37
38
|
}
|
|
38
39
|
|
|
39
40
|
type LeafStrategy = (ctx: LeafContext) => Array<ExportNode>
|
|
@@ -99,9 +100,10 @@ type LeafWalkParams = {
|
|
|
99
100
|
}
|
|
100
101
|
|
|
101
102
|
/**
|
|
102
|
-
* Post-order walk that
|
|
103
|
+
* Post-order walk that yields a barrel per visited directory.
|
|
104
|
+
* Returns the list of leaf file paths collected in this subtree (used by the parent call).
|
|
103
105
|
*/
|
|
104
|
-
function walkAllOrNamed(node: BuildTree, params: LeafWalkParams, isRoot: boolean
|
|
106
|
+
function* walkAllOrNamed(node: BuildTree, params: LeafWalkParams, isRoot: boolean): Generator<FileNode, Array<string>> {
|
|
105
107
|
const subtreeLeaves: Array<string> = []
|
|
106
108
|
|
|
107
109
|
for (const child of node.children) {
|
|
@@ -110,26 +112,26 @@ function walkAllOrNamed(node: BuildTree, params: LeafWalkParams, isRoot: boolean
|
|
|
110
112
|
continue
|
|
111
113
|
}
|
|
112
114
|
|
|
113
|
-
const childLeaves = walkAllOrNamed(child, params, false
|
|
115
|
+
const childLeaves = yield* walkAllOrNamed(child, params, false)
|
|
114
116
|
for (const leaf of childLeaves) subtreeLeaves.push(leaf)
|
|
115
117
|
}
|
|
116
118
|
|
|
117
119
|
if (!isRoot && !params.recursive) return subtreeLeaves
|
|
118
120
|
|
|
119
|
-
const exports = subtreeLeaves.flatMap((leafPath) => params.strategy({ dirPath: node.path, leafPath, sourceFile: params.sourceFiles.get(leafPath) }))
|
|
121
|
+
const exports = subtreeLeaves.flatMap((leafPath) => params.strategy({ dirPath: node.path, leafPath, sourceFile: params.sourceFiles.get(leafPath) ?? null }))
|
|
120
122
|
|
|
121
123
|
if (exports.length > 0) {
|
|
122
|
-
|
|
124
|
+
yield makeBarrel(node.path, exports)
|
|
123
125
|
}
|
|
124
126
|
|
|
125
127
|
return subtreeLeaves
|
|
126
128
|
}
|
|
127
129
|
|
|
128
130
|
/**
|
|
129
|
-
* Recursive walk that
|
|
131
|
+
* Recursive walk that yields one barrel per directory, re-exporting files and sub-barrels.
|
|
130
132
|
* Used when nested: true.
|
|
131
133
|
*/
|
|
132
|
-
function walkNested(node: BuildTree
|
|
134
|
+
function* walkNested(node: BuildTree): Generator<FileNode> {
|
|
133
135
|
const exports: Array<ExportNode> = []
|
|
134
136
|
|
|
135
137
|
for (const child of node.children) {
|
|
@@ -139,12 +141,12 @@ function walkNested(node: BuildTree, out: Array<FileNode>): void {
|
|
|
139
141
|
continue
|
|
140
142
|
}
|
|
141
143
|
|
|
142
|
-
walkNested(child
|
|
144
|
+
yield* walkNested(child)
|
|
143
145
|
exports.push(createExport({ path: toRelativeModulePath(node.path, `${child.path}${BARREL_SUFFIX}`) }))
|
|
144
146
|
}
|
|
145
147
|
|
|
146
148
|
if (exports.length > 0) {
|
|
147
|
-
|
|
149
|
+
yield makeBarrel(node.path, exports)
|
|
148
150
|
}
|
|
149
151
|
}
|
|
150
152
|
|
|
@@ -204,24 +206,53 @@ type GetBarrelFilesParams = {
|
|
|
204
206
|
}
|
|
205
207
|
|
|
206
208
|
/**
|
|
207
|
-
*
|
|
209
|
+
* Yields barrel `FileNode`s for the directory rooted at `outputPath`.
|
|
210
|
+
*
|
|
211
|
+
* @example
|
|
212
|
+
* ```ts
|
|
213
|
+
* for (const file of getBarrelFiles({ outputPath, files, barrelType })) {
|
|
214
|
+
* upsertFile(file)
|
|
215
|
+
* }
|
|
216
|
+
* // or collect into an array
|
|
217
|
+
* const barrels = [...getBarrelFiles({ outputPath, files, barrelType })]
|
|
218
|
+
* ```
|
|
208
219
|
*/
|
|
209
|
-
export function getBarrelFiles({ outputPath, files, barrelType, nested = false, recursive = false }: GetBarrelFilesParams):
|
|
220
|
+
export function* getBarrelFiles({ outputPath, files, barrelType, nested = false, recursive = false }: GetBarrelFilesParams): Generator<FileNode> {
|
|
210
221
|
const { sourceFiles, paths } = indexRelevantFiles(files, outputPath)
|
|
211
|
-
if (paths.length === 0) return
|
|
222
|
+
if (paths.length === 0) return
|
|
212
223
|
|
|
213
224
|
const tree = buildTree(outputPath, paths)
|
|
214
|
-
const result: Array<FileNode> = []
|
|
215
225
|
|
|
216
|
-
// Use nested walk for hierarchical barrel structure
|
|
217
226
|
if (nested) {
|
|
218
|
-
walkNested(tree
|
|
219
|
-
return
|
|
227
|
+
yield* walkNested(tree)
|
|
228
|
+
return
|
|
220
229
|
}
|
|
221
230
|
|
|
222
231
|
const strategy = LEAF_STRATEGIES.get(barrelType)
|
|
223
|
-
if (!strategy) return
|
|
232
|
+
if (!strategy) return
|
|
224
233
|
|
|
225
|
-
walkAllOrNamed(tree, { sourceFiles, strategy, recursive }, true
|
|
226
|
-
|
|
234
|
+
yield* walkAllOrNamed(tree, { sourceFiles, strategy, recursive }, true)
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Builds a POSIX-normalized prefix for a plugin's output. A directory output gets a trailing `/`,
|
|
239
|
+
* while a `mode: 'file'` output (the path is the file itself) gets the exact path with no trailing `/`.
|
|
240
|
+
*
|
|
241
|
+
* Used to detect (and later exclude) files generated by plugins that opted out of the root barrel.
|
|
242
|
+
*/
|
|
243
|
+
export function getPluginOutputPrefix(plugin: NormalizedPlugin, config: Config): string {
|
|
244
|
+
const resolved = toPosixPath(resolve(config.root, config.output.path, plugin.options.output.path))
|
|
245
|
+
return plugin.options.output.mode === 'file' ? resolved : `${resolved}/`
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Returns `true` when `filePath` lives under any of the given excluded prefixes. A prefix with a
|
|
250
|
+
* trailing `/` matches a directory subtree, and a prefix without one matches that exact file
|
|
251
|
+
* (used for `mode: 'file'` outputs).
|
|
252
|
+
*
|
|
253
|
+
* Both sides are POSIX-normalized so Windows backslash paths match correctly.
|
|
254
|
+
*/
|
|
255
|
+
export function isExcludedPath(filePath: string, prefixes: ReadonlySet<string>): boolean {
|
|
256
|
+
const normalized = toPosixPath(filePath)
|
|
257
|
+
return prefixes.values().some((prefix) => (prefix.endsWith('/') ? normalized.startsWith(prefix) : normalized === prefix))
|
|
227
258
|
}
|
package/src/constants.ts
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { resolve } from 'node:path'
|
|
2
|
-
import type { Config, NormalizedPlugin } from '@kubb/core'
|
|
3
|
-
import { toPosixPath } from '@internals/utils'
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* Builds a POSIX-normalized prefix for a plugin's output directory, with a trailing `/`.
|
|
7
|
-
*
|
|
8
|
-
* Used to detect (and later exclude) files generated by plugins that opted out of the root barrel.
|
|
9
|
-
*/
|
|
10
|
-
export function getPluginOutputPrefix(plugin: NormalizedPlugin, config: Config): string {
|
|
11
|
-
return `${toPosixPath(resolve(config.root, config.output.path, plugin.options.output.path))}/`
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Returns `true` when `filePath` lives under any of the given excluded directory prefixes.
|
|
16
|
-
*
|
|
17
|
-
* Both sides are POSIX-normalized so Windows backslash paths match correctly.
|
|
18
|
-
*/
|
|
19
|
-
export function isExcludedPath(filePath: string, prefixes: ReadonlySet<string>): boolean {
|
|
20
|
-
const normalized = toPosixPath(filePath)
|
|
21
|
-
return prefixes.values().some((prefix) => normalized.startsWith(prefix))
|
|
22
|
-
}
|
|
File without changes
|