@kubb/core 4.36.1 → 5.0.0-alpha.10
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/{types-D30QAz2y.d.ts → PluginDriver-BkFepPdm.d.ts} +354 -291
- package/dist/hooks.cjs +85 -8
- package/dist/hooks.cjs.map +1 -1
- package/dist/hooks.d.ts +66 -4
- package/dist/hooks.js +83 -8
- package/dist/hooks.js.map +1 -1
- package/dist/index.cjs +346 -315
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +91 -77
- package/dist/index.js +338 -305
- package/dist/index.js.map +1 -1
- package/package.json +7 -7
- package/src/Kubb.ts +27 -55
- package/src/{PluginManager.ts → PluginDriver.ts} +69 -82
- package/src/build.ts +32 -33
- package/src/constants.ts +1 -1
- package/src/createAdapter.ts +25 -0
- package/src/createPlugin.ts +28 -0
- package/src/createStorage.ts +58 -0
- package/src/defineGenerator.ts +134 -0
- package/src/defineLogger.ts +13 -3
- package/src/defineResolver.ts +131 -0
- package/src/hooks/index.ts +2 -1
- package/src/hooks/useKubb.ts +143 -0
- package/src/hooks/useMode.ts +5 -2
- package/src/hooks/usePlugin.ts +5 -2
- package/src/hooks/usePluginDriver.ts +11 -0
- package/src/index.ts +7 -7
- package/src/storages/fsStorage.ts +2 -2
- package/src/storages/memoryStorage.ts +2 -2
- package/src/types.ts +94 -48
- package/src/utils/FunctionParams.ts +2 -2
- package/src/utils/TreeNode.ts +1 -1
- package/src/utils/formatters.ts +1 -1
- package/src/utils/getBarrelFiles.ts +73 -11
- package/src/utils/getConfigs.ts +3 -21
- package/src/utils/linters.ts +1 -1
- package/src/utils/packageJSON.ts +61 -0
- package/src/BarrelManager.ts +0 -74
- package/src/PackageManager.ts +0 -180
- package/src/PromiseManager.ts +0 -40
- package/src/defineAdapter.ts +0 -22
- package/src/definePlugin.ts +0 -12
- package/src/defineStorage.ts +0 -56
- package/src/errors.ts +0 -1
- package/src/hooks/usePluginManager.ts +0 -8
- package/src/utils/getPlugins.ts +0 -23
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kubb/core",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "5.0.0-alpha.10",
|
|
4
4
|
"description": "Core functionality for Kubb's plugin-based code generation system, providing the foundation for transforming OpenAPI specifications.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"typescript",
|
|
@@ -64,14 +64,14 @@
|
|
|
64
64
|
}
|
|
65
65
|
],
|
|
66
66
|
"dependencies": {
|
|
67
|
-
"@kubb/fabric-core": "0.
|
|
68
|
-
"@kubb/react-fabric": "0.
|
|
67
|
+
"@kubb/fabric-core": "0.14.0",
|
|
68
|
+
"@kubb/react-fabric": "0.14.0",
|
|
69
69
|
"empathic": "^2.0.0",
|
|
70
70
|
"fflate": "^0.8.2",
|
|
71
71
|
"remeda": "^2.33.6",
|
|
72
72
|
"semver": "^7.7.4",
|
|
73
73
|
"tinyexec": "^1.0.4",
|
|
74
|
-
"@kubb/ast": "
|
|
74
|
+
"@kubb/ast": "5.0.0-alpha.10"
|
|
75
75
|
},
|
|
76
76
|
"devDependencies": {
|
|
77
77
|
"@types/semver": "^7.7.1",
|
|
@@ -79,11 +79,11 @@
|
|
|
79
79
|
"@internals/utils": "0.0.0"
|
|
80
80
|
},
|
|
81
81
|
"peerDependencies": {
|
|
82
|
-
"@kubb/fabric-core": "0.
|
|
83
|
-
"@kubb/react-fabric": "0.
|
|
82
|
+
"@kubb/fabric-core": "0.14.0",
|
|
83
|
+
"@kubb/react-fabric": "0.14.0"
|
|
84
84
|
},
|
|
85
85
|
"engines": {
|
|
86
|
-
"node": ">=
|
|
86
|
+
"node": ">=22"
|
|
87
87
|
},
|
|
88
88
|
"publishConfig": {
|
|
89
89
|
"access": "public",
|
package/src/Kubb.ts
CHANGED
|
@@ -1,36 +1,32 @@
|
|
|
1
1
|
import type { KubbFile } from '@kubb/fabric-core/types'
|
|
2
|
-
import type { Strategy } from './
|
|
2
|
+
import type { Strategy } from './PluginDriver.ts'
|
|
3
3
|
import type { Config, Plugin, PluginLifecycleHooks } from './types'
|
|
4
4
|
|
|
5
|
-
type
|
|
5
|
+
type DebugInfo = {
|
|
6
6
|
date: Date
|
|
7
|
-
logs: string
|
|
7
|
+
logs: Array<string>
|
|
8
8
|
fileName?: string
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
type
|
|
11
|
+
type HookProgress<H extends PluginLifecycleHooks = PluginLifecycleHooks> = {
|
|
12
12
|
hookName: H
|
|
13
13
|
plugins: Array<Plugin>
|
|
14
14
|
}
|
|
15
15
|
|
|
16
|
-
type
|
|
17
|
-
hookName: H
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
type ExecutingMeta<H extends PluginLifecycleHooks = PluginLifecycleHooks> = {
|
|
16
|
+
type HookExecution<H extends PluginLifecycleHooks = PluginLifecycleHooks> = {
|
|
21
17
|
strategy: Strategy
|
|
22
18
|
hookName: H
|
|
23
19
|
plugin: Plugin
|
|
24
|
-
parameters?: unknown
|
|
20
|
+
parameters?: Array<unknown>
|
|
25
21
|
output?: unknown
|
|
26
22
|
}
|
|
27
23
|
|
|
28
|
-
type
|
|
24
|
+
type HookResult<H extends PluginLifecycleHooks = PluginLifecycleHooks> = {
|
|
29
25
|
duration: number
|
|
30
26
|
strategy: Strategy
|
|
31
27
|
hookName: H
|
|
32
28
|
plugin: Plugin
|
|
33
|
-
parameters?: unknown
|
|
29
|
+
parameters?: Array<unknown>
|
|
34
30
|
output?: unknown
|
|
35
31
|
}
|
|
36
32
|
|
|
@@ -40,7 +36,7 @@ type ExecutedMeta<H extends PluginLifecycleHooks = PluginLifecycleHooks> = {
|
|
|
40
36
|
*
|
|
41
37
|
* @example
|
|
42
38
|
* ```typescript
|
|
43
|
-
* import type { AsyncEventEmitter } from '@
|
|
39
|
+
* import type { AsyncEventEmitter } from '@internals/utils'
|
|
44
40
|
* import type { KubbEvents } from '@kubb/core'
|
|
45
41
|
*
|
|
46
42
|
* const events: AsyncEventEmitter<KubbEvents> = new AsyncEventEmitter()
|
|
@@ -59,7 +55,6 @@ export interface KubbEvents {
|
|
|
59
55
|
* Emitted at the beginning of the Kubb lifecycle, before any code generation starts.
|
|
60
56
|
*/
|
|
61
57
|
'lifecycle:start': [version: string]
|
|
62
|
-
|
|
63
58
|
/**
|
|
64
59
|
* Emitted at the end of the Kubb lifecycle, after all code generation is complete.
|
|
65
60
|
*/
|
|
@@ -69,7 +64,6 @@ export interface KubbEvents {
|
|
|
69
64
|
* Emitted when configuration loading starts.
|
|
70
65
|
*/
|
|
71
66
|
'config:start': []
|
|
72
|
-
|
|
73
67
|
/**
|
|
74
68
|
* Emitted when configuration loading is complete.
|
|
75
69
|
*/
|
|
@@ -79,24 +73,22 @@ export interface KubbEvents {
|
|
|
79
73
|
* Emitted when code generation phase starts.
|
|
80
74
|
*/
|
|
81
75
|
'generation:start': [config: Config]
|
|
82
|
-
|
|
83
76
|
/**
|
|
84
77
|
* Emitted when code generation phase completes.
|
|
85
78
|
*/
|
|
86
|
-
'generation:end': [
|
|
87
|
-
|
|
79
|
+
'generation:end': [config: Config, files: Array<KubbFile.ResolvedFile>, sources: Map<KubbFile.Path, string>]
|
|
88
80
|
/**
|
|
89
81
|
* Emitted with a summary of the generation results.
|
|
90
82
|
* Contains summary lines, title, and success status.
|
|
91
83
|
*/
|
|
92
84
|
'generation:summary': [
|
|
93
|
-
|
|
85
|
+
config: Config,
|
|
94
86
|
{
|
|
95
87
|
failedPlugins: Set<{ plugin: Plugin; error: Error }>
|
|
96
88
|
status: 'success' | 'failed'
|
|
97
89
|
hrStart: [number, number]
|
|
98
90
|
filesCreated: number
|
|
99
|
-
pluginTimings?: Map<
|
|
91
|
+
pluginTimings?: Map<Plugin['name'], number>
|
|
100
92
|
},
|
|
101
93
|
]
|
|
102
94
|
|
|
@@ -104,7 +96,6 @@ export interface KubbEvents {
|
|
|
104
96
|
* Emitted when code formatting starts (e.g., running Biome or Prettier).
|
|
105
97
|
*/
|
|
106
98
|
'format:start': []
|
|
107
|
-
|
|
108
99
|
/**
|
|
109
100
|
* Emitted when code formatting completes.
|
|
110
101
|
*/
|
|
@@ -114,7 +105,6 @@ export interface KubbEvents {
|
|
|
114
105
|
* Emitted when linting starts.
|
|
115
106
|
*/
|
|
116
107
|
'lint:start': []
|
|
117
|
-
|
|
118
108
|
/**
|
|
119
109
|
* Emitted when linting completes.
|
|
120
110
|
*/
|
|
@@ -124,29 +114,20 @@ export interface KubbEvents {
|
|
|
124
114
|
* Emitted when plugin hooks execution starts.
|
|
125
115
|
*/
|
|
126
116
|
'hooks:start': []
|
|
127
|
-
|
|
128
117
|
/**
|
|
129
118
|
* Emitted when plugin hooks execution completes.
|
|
130
119
|
*/
|
|
131
120
|
'hooks:end': []
|
|
132
121
|
|
|
133
122
|
/**
|
|
134
|
-
* Emitted when a single hook execution starts
|
|
123
|
+
* Emitted when a single hook execution starts (e.g., format or lint).
|
|
135
124
|
* The callback should be invoked when the command completes.
|
|
136
125
|
*/
|
|
137
126
|
'hook:start': [{ id?: string; command: string; args?: readonly string[] }]
|
|
138
127
|
/**
|
|
139
128
|
* Emitted when a single hook execution completes.
|
|
140
129
|
*/
|
|
141
|
-
'hook:end': [
|
|
142
|
-
{
|
|
143
|
-
id?: string
|
|
144
|
-
command: string
|
|
145
|
-
args?: readonly string[]
|
|
146
|
-
success: boolean
|
|
147
|
-
error: Error | null
|
|
148
|
-
},
|
|
149
|
-
]
|
|
130
|
+
'hook:end': [{ id?: string; command: string; args?: readonly string[]; success: boolean; error: Error | null }]
|
|
150
131
|
|
|
151
132
|
/**
|
|
152
133
|
* Emitted when a new version of Kubb is available.
|
|
@@ -157,49 +138,44 @@ export interface KubbEvents {
|
|
|
157
138
|
* Informational message event.
|
|
158
139
|
*/
|
|
159
140
|
info: [message: string, info?: string]
|
|
160
|
-
|
|
161
141
|
/**
|
|
162
142
|
* Error event. Emitted when an error occurs during code generation.
|
|
163
143
|
*/
|
|
164
144
|
error: [error: Error, meta?: Record<string, unknown>]
|
|
165
|
-
|
|
166
145
|
/**
|
|
167
146
|
* Success message event.
|
|
168
147
|
*/
|
|
169
148
|
success: [message: string, info?: string]
|
|
170
|
-
|
|
171
149
|
/**
|
|
172
150
|
* Warning message event.
|
|
173
151
|
*/
|
|
174
152
|
warn: [message: string, info?: string]
|
|
175
|
-
|
|
176
153
|
/**
|
|
177
154
|
* Debug event for detailed logging.
|
|
178
155
|
* Contains timestamp, log messages, and optional filename.
|
|
179
156
|
*/
|
|
180
|
-
debug: [
|
|
157
|
+
debug: [info: DebugInfo]
|
|
181
158
|
|
|
182
159
|
/**
|
|
183
160
|
* Emitted when file processing starts.
|
|
184
161
|
* Contains the list of files to be processed.
|
|
185
162
|
*/
|
|
186
163
|
'files:processing:start': [files: Array<KubbFile.ResolvedFile>]
|
|
187
|
-
|
|
188
164
|
/**
|
|
189
165
|
* Emitted for each file being processed, providing progress updates.
|
|
190
166
|
* Contains processed count, total count, percentage, and file details.
|
|
191
167
|
*/
|
|
192
168
|
'file:processing:update': [
|
|
193
169
|
{
|
|
194
|
-
/** Number of files processed so far */
|
|
170
|
+
/** Number of files processed so far. */
|
|
195
171
|
processed: number
|
|
196
|
-
/** Total number of files to process */
|
|
172
|
+
/** Total number of files to process. */
|
|
197
173
|
total: number
|
|
198
|
-
/** Processing percentage (0
|
|
174
|
+
/** Processing percentage (0–100). */
|
|
199
175
|
percentage: number
|
|
200
|
-
/** Optional source identifier */
|
|
176
|
+
/** Optional source identifier. */
|
|
201
177
|
source?: string
|
|
202
|
-
/** The file being processed */
|
|
178
|
+
/** The file being processed. */
|
|
203
179
|
file: KubbFile.ResolvedFile
|
|
204
180
|
/**
|
|
205
181
|
* Kubb configuration (not present in Fabric).
|
|
@@ -208,45 +184,41 @@ export interface KubbEvents {
|
|
|
208
184
|
config: Config
|
|
209
185
|
},
|
|
210
186
|
]
|
|
211
|
-
|
|
212
187
|
/**
|
|
213
188
|
* Emitted when file processing completes.
|
|
214
189
|
* Contains the list of processed files.
|
|
215
190
|
*/
|
|
216
|
-
'files:processing:end': [files: KubbFile.ResolvedFile
|
|
191
|
+
'files:processing:end': [files: Array<KubbFile.ResolvedFile>]
|
|
217
192
|
|
|
218
193
|
/**
|
|
219
194
|
* Emitted when a plugin starts executing.
|
|
220
195
|
*/
|
|
221
196
|
'plugin:start': [plugin: Plugin]
|
|
222
|
-
|
|
223
197
|
/**
|
|
224
198
|
* Emitted when a plugin completes execution.
|
|
225
|
-
* Duration in ms
|
|
199
|
+
* Duration in ms.
|
|
226
200
|
*/
|
|
227
|
-
'plugin:end': [plugin: Plugin,
|
|
201
|
+
'plugin:end': [plugin: Plugin, result: { duration: number; success: boolean; error?: Error }]
|
|
228
202
|
|
|
229
203
|
/**
|
|
230
204
|
* Emitted when plugin hook progress tracking starts.
|
|
231
205
|
* Contains the hook name and list of plugins to execute.
|
|
232
206
|
*/
|
|
233
|
-
'plugins:hook:progress:start': [
|
|
234
|
-
|
|
207
|
+
'plugins:hook:progress:start': [progress: HookProgress]
|
|
235
208
|
/**
|
|
236
209
|
* Emitted when plugin hook progress tracking ends.
|
|
237
210
|
* Contains the hook name that completed.
|
|
238
211
|
*/
|
|
239
|
-
'plugins:hook:progress:end': [
|
|
212
|
+
'plugins:hook:progress:end': [{ hookName: PluginLifecycleHooks }]
|
|
240
213
|
|
|
241
214
|
/**
|
|
242
215
|
* Emitted when a plugin hook starts processing.
|
|
243
216
|
* Contains strategy, hook name, plugin, parameters, and output.
|
|
244
217
|
*/
|
|
245
|
-
'plugins:hook:processing:start': [
|
|
246
|
-
|
|
218
|
+
'plugins:hook:processing:start': [execution: HookExecution]
|
|
247
219
|
/**
|
|
248
220
|
* Emitted when a plugin hook completes processing.
|
|
249
221
|
* Contains duration, strategy, hook name, plugin, parameters, and output.
|
|
250
222
|
*/
|
|
251
|
-
'plugins:hook:processing:end': [
|
|
223
|
+
'plugins:hook:processing:end': [result: HookResult]
|
|
252
224
|
}
|
|
@@ -1,15 +1,14 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { basename, extname, resolve } from 'node:path'
|
|
2
2
|
import { performance } from 'node:perf_hooks'
|
|
3
3
|
import type { AsyncEventEmitter } from '@internals/utils'
|
|
4
|
-
import { setUniqueName, transformReservedWord } from '@internals/utils'
|
|
4
|
+
import { isPromiseRejectedResult, setUniqueName, transformReservedWord, ValidationPluginError } from '@internals/utils'
|
|
5
5
|
import type { RootNode } from '@kubb/ast/types'
|
|
6
|
-
import type { KubbFile } from '@kubb/fabric-core/types'
|
|
7
|
-
import type { Fabric } from '@kubb/react-fabric'
|
|
6
|
+
import type { Fabric as FabricType, KubbFile } from '@kubb/fabric-core/types'
|
|
8
7
|
import { CORE_PLUGIN_NAME, DEFAULT_STUDIO_URL } from './constants.ts'
|
|
9
8
|
import { openInStudio as openInStudioFn } from './devtools.ts'
|
|
10
|
-
|
|
11
|
-
import { isPromiseRejectedResult, PromiseManager } from './PromiseManager.ts'
|
|
9
|
+
|
|
12
10
|
import type {
|
|
11
|
+
Adapter,
|
|
13
12
|
Config,
|
|
14
13
|
DevtoolsOptions,
|
|
15
14
|
KubbEvents,
|
|
@@ -24,6 +23,7 @@ import type {
|
|
|
24
23
|
ResolvePathParams,
|
|
25
24
|
UserPlugin,
|
|
26
25
|
} from './types.ts'
|
|
26
|
+
import { hookFirst, hookParallel, hookSeq } from './utils/executeStrategies.ts'
|
|
27
27
|
|
|
28
28
|
type RequiredPluginLifecycle = Required<PluginLifecycle>
|
|
29
29
|
|
|
@@ -39,7 +39,7 @@ type SafeParseResult<H extends PluginLifecycleHooks, Result = ReturnType<ParseRe
|
|
|
39
39
|
// inspired by: https://github.com/rollup/rollup/blob/master/src/utils/PluginDriver.ts#
|
|
40
40
|
|
|
41
41
|
type Options = {
|
|
42
|
-
fabric:
|
|
42
|
+
fabric: FabricType
|
|
43
43
|
events: AsyncEventEmitter<KubbEvents>
|
|
44
44
|
/**
|
|
45
45
|
* @default Number.POSITIVE_INFINITY
|
|
@@ -47,11 +47,11 @@ type Options = {
|
|
|
47
47
|
concurrency?: number
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
-
type
|
|
50
|
+
export type GetFileOptions<TOptions = object> = {
|
|
51
51
|
name: string
|
|
52
52
|
mode?: KubbFile.Mode
|
|
53
53
|
extname: KubbFile.Extname
|
|
54
|
-
|
|
54
|
+
pluginName: string
|
|
55
55
|
options?: TOptions
|
|
56
56
|
}
|
|
57
57
|
|
|
@@ -59,10 +59,12 @@ export function getMode(fileOrFolder: string | undefined | null): KubbFile.Mode
|
|
|
59
59
|
if (!fileOrFolder) {
|
|
60
60
|
return 'split'
|
|
61
61
|
}
|
|
62
|
-
return
|
|
62
|
+
return extname(fileOrFolder) ? 'single' : 'split'
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
-
|
|
65
|
+
const hookFirstNullCheck = (state: unknown) => !!(state as SafeParseResult<'resolveName'> | null)?.result
|
|
66
|
+
|
|
67
|
+
export class PluginDriver {
|
|
66
68
|
readonly config: Config
|
|
67
69
|
readonly options: Options
|
|
68
70
|
|
|
@@ -71,18 +73,15 @@ export class PluginManager {
|
|
|
71
73
|
* the build pipeline after the adapter's `parse()` resolves.
|
|
72
74
|
*/
|
|
73
75
|
rootNode: RootNode | undefined = undefined
|
|
76
|
+
adapter: Adapter | undefined = undefined
|
|
74
77
|
#studioIsOpen = false
|
|
75
78
|
|
|
76
79
|
readonly #plugins = new Set<Plugin>()
|
|
77
80
|
readonly #usedPluginNames: Record<string, number> = {}
|
|
78
|
-
readonly #promiseManager
|
|
79
81
|
|
|
80
82
|
constructor(config: Config, options: Options) {
|
|
81
83
|
this.config = config
|
|
82
84
|
this.options = options
|
|
83
|
-
this.#promiseManager = new PromiseManager({
|
|
84
|
-
nullCheck: (state: SafeParseResult<'resolveName'> | null) => !!state?.result,
|
|
85
|
-
})
|
|
86
85
|
;[...(config.plugins || [])].forEach((plugin) => {
|
|
87
86
|
const parsedPlugin = this.#parse(plugin as UserPlugin)
|
|
88
87
|
|
|
@@ -96,15 +95,15 @@ export class PluginManager {
|
|
|
96
95
|
|
|
97
96
|
getContext<TOptions extends PluginFactoryOptions>(plugin: Plugin<TOptions>): PluginContext<TOptions> & Record<string, unknown> {
|
|
98
97
|
const plugins = [...this.#plugins]
|
|
99
|
-
const
|
|
98
|
+
const driver = this
|
|
100
99
|
|
|
101
100
|
const baseContext = {
|
|
102
101
|
fabric: this.options.fabric,
|
|
103
102
|
config: this.config,
|
|
104
103
|
plugin,
|
|
105
104
|
events: this.options.events,
|
|
106
|
-
|
|
107
|
-
mode: getMode(
|
|
105
|
+
driver: this,
|
|
106
|
+
mode: getMode(resolve(this.config.root, this.config.output.path)),
|
|
108
107
|
addFile: async (...files: Array<KubbFile.File>) => {
|
|
109
108
|
await this.options.fabric.addFile(...files)
|
|
110
109
|
},
|
|
@@ -112,26 +111,29 @@ export class PluginManager {
|
|
|
112
111
|
await this.options.fabric.upsertFile(...files)
|
|
113
112
|
},
|
|
114
113
|
get rootNode(): RootNode | undefined {
|
|
115
|
-
return
|
|
114
|
+
return driver.rootNode
|
|
115
|
+
},
|
|
116
|
+
get adapter(): Adapter | undefined {
|
|
117
|
+
return driver.adapter
|
|
116
118
|
},
|
|
117
119
|
openInStudio(options?: DevtoolsOptions) {
|
|
118
|
-
if (
|
|
119
|
-
|
|
120
|
+
if (!driver.config.devtools || driver.#studioIsOpen) {
|
|
121
|
+
return
|
|
120
122
|
}
|
|
121
123
|
|
|
122
|
-
if (
|
|
123
|
-
throw new Error('
|
|
124
|
+
if (typeof driver.config.devtools !== 'object') {
|
|
125
|
+
throw new Error('Devtools must be an object')
|
|
124
126
|
}
|
|
125
127
|
|
|
126
|
-
if (
|
|
127
|
-
|
|
128
|
+
if (!driver.rootNode || !driver.adapter) {
|
|
129
|
+
throw new Error('adapter is not defined, make sure you have set the parser in kubb.config.ts')
|
|
128
130
|
}
|
|
129
131
|
|
|
130
|
-
|
|
132
|
+
driver.#studioIsOpen = true
|
|
131
133
|
|
|
132
|
-
const studioUrl =
|
|
134
|
+
const studioUrl = driver.config.devtools?.studioUrl ?? DEFAULT_STUDIO_URL
|
|
133
135
|
|
|
134
|
-
return openInStudioFn(
|
|
136
|
+
return openInStudioFn(driver.rootNode, studioUrl, options)
|
|
135
137
|
},
|
|
136
138
|
} as unknown as PluginContext<TOptions>
|
|
137
139
|
|
|
@@ -158,19 +160,25 @@ export class PluginManager {
|
|
|
158
160
|
return this.#getSortedPlugins()
|
|
159
161
|
}
|
|
160
162
|
|
|
161
|
-
getFile<TOptions = object>({ name, mode, extname,
|
|
162
|
-
const
|
|
163
|
-
|
|
163
|
+
getFile<TOptions = object>({ name, mode, extname, pluginName, options }: GetFileOptions<TOptions>): KubbFile.File<{ pluginName: string }> {
|
|
164
|
+
const resolvedName = mode ? (mode === 'single' ? '' : this.resolveName({ name, pluginName, type: 'file' })) : name
|
|
165
|
+
|
|
166
|
+
const path = this.resolvePath({
|
|
167
|
+
baseName: `${resolvedName}${extname}` as const,
|
|
168
|
+
mode,
|
|
169
|
+
pluginName,
|
|
170
|
+
options,
|
|
171
|
+
})
|
|
164
172
|
|
|
165
173
|
if (!path) {
|
|
166
|
-
throw new Error(`Filepath should be defined for resolvedName "${
|
|
174
|
+
throw new Error(`Filepath should be defined for resolvedName "${resolvedName}" and pluginName "${pluginName}"`)
|
|
167
175
|
}
|
|
168
176
|
|
|
169
177
|
return {
|
|
170
178
|
path,
|
|
171
|
-
baseName,
|
|
179
|
+
baseName: basename(path) as KubbFile.File['baseName'],
|
|
172
180
|
meta: {
|
|
173
|
-
|
|
181
|
+
pluginName,
|
|
174
182
|
},
|
|
175
183
|
sources: [],
|
|
176
184
|
imports: [],
|
|
@@ -179,12 +187,12 @@ export class PluginManager {
|
|
|
179
187
|
}
|
|
180
188
|
|
|
181
189
|
resolvePath = <TOptions = object>(params: ResolvePathParams<TOptions>): KubbFile.Path => {
|
|
182
|
-
const root =
|
|
183
|
-
const defaultPath =
|
|
190
|
+
const root = resolve(this.config.root, this.config.output.path)
|
|
191
|
+
const defaultPath = resolve(root, params.baseName)
|
|
184
192
|
|
|
185
|
-
if (params.
|
|
193
|
+
if (params.pluginName) {
|
|
186
194
|
const paths = this.hookForPluginSync({
|
|
187
|
-
|
|
195
|
+
pluginName: params.pluginName,
|
|
188
196
|
hookName: 'resolvePath',
|
|
189
197
|
parameters: [params.baseName, params.mode, params.options as object],
|
|
190
198
|
})
|
|
@@ -201,9 +209,9 @@ export class PluginManager {
|
|
|
201
209
|
}
|
|
202
210
|
//TODO refactor by using the order of plugins and the cache of the fileManager instead of guessing and recreating the name/path
|
|
203
211
|
resolveName = (params: ResolveNameParams): string => {
|
|
204
|
-
if (params.
|
|
212
|
+
if (params.pluginName) {
|
|
205
213
|
const names = this.hookForPluginSync({
|
|
206
|
-
|
|
214
|
+
pluginName: params.pluginName,
|
|
207
215
|
hookName: 'resolveName',
|
|
208
216
|
parameters: [params.name.trim(), params.type],
|
|
209
217
|
})
|
|
@@ -225,15 +233,15 @@ export class PluginManager {
|
|
|
225
233
|
* Run a specific hookName for plugin x.
|
|
226
234
|
*/
|
|
227
235
|
async hookForPlugin<H extends PluginLifecycleHooks>({
|
|
228
|
-
|
|
236
|
+
pluginName,
|
|
229
237
|
hookName,
|
|
230
238
|
parameters,
|
|
231
239
|
}: {
|
|
232
|
-
|
|
240
|
+
pluginName: string
|
|
233
241
|
hookName: H
|
|
234
242
|
parameters: PluginParameter<H>
|
|
235
243
|
}): Promise<Array<ReturnType<ParseResult<H>> | null>> {
|
|
236
|
-
const plugins = this.
|
|
244
|
+
const plugins = this.getPluginsByName(hookName, pluginName)
|
|
237
245
|
|
|
238
246
|
this.events.emit('plugins:hook:progress:start', {
|
|
239
247
|
hookName,
|
|
@@ -264,15 +272,15 @@ export class PluginManager {
|
|
|
264
272
|
*/
|
|
265
273
|
|
|
266
274
|
hookForPluginSync<H extends PluginLifecycleHooks>({
|
|
267
|
-
|
|
275
|
+
pluginName,
|
|
268
276
|
hookName,
|
|
269
277
|
parameters,
|
|
270
278
|
}: {
|
|
271
|
-
|
|
279
|
+
pluginName: string
|
|
272
280
|
hookName: H
|
|
273
281
|
parameters: PluginParameter<H>
|
|
274
282
|
}): Array<ReturnType<ParseResult<H>>> | null {
|
|
275
|
-
const plugins = this.
|
|
283
|
+
const plugins = this.getPluginsByName(hookName, pluginName)
|
|
276
284
|
|
|
277
285
|
const result = plugins
|
|
278
286
|
.map((plugin) => {
|
|
@@ -322,7 +330,7 @@ export class PluginManager {
|
|
|
322
330
|
}
|
|
323
331
|
})
|
|
324
332
|
|
|
325
|
-
const result = await
|
|
333
|
+
const result = await hookFirst(promises, hookFirstNullCheck)
|
|
326
334
|
|
|
327
335
|
this.events.emit('plugins:hook:progress:end', { hookName })
|
|
328
336
|
|
|
@@ -392,9 +400,7 @@ export class PluginManager {
|
|
|
392
400
|
}
|
|
393
401
|
})
|
|
394
402
|
|
|
395
|
-
const results = await
|
|
396
|
-
concurrency: this.options.concurrency,
|
|
397
|
-
})
|
|
403
|
+
const results = await hookParallel(promises, this.options.concurrency)
|
|
398
404
|
|
|
399
405
|
results.forEach((result, index) => {
|
|
400
406
|
if (isPromiseRejectedResult<Error>(result)) {
|
|
@@ -440,7 +446,7 @@ export class PluginManager {
|
|
|
440
446
|
})
|
|
441
447
|
})
|
|
442
448
|
|
|
443
|
-
await
|
|
449
|
+
await hookSeq(promises)
|
|
444
450
|
|
|
445
451
|
this.events.emit('plugins:hook:progress:end', { hookName })
|
|
446
452
|
}
|
|
@@ -456,7 +462,12 @@ export class PluginManager {
|
|
|
456
462
|
return plugins
|
|
457
463
|
.map((plugin) => {
|
|
458
464
|
if (plugin.pre) {
|
|
459
|
-
|
|
465
|
+
let missingPlugins = plugin.pre.filter((pluginName) => !plugins.find((pluginToFind) => pluginToFind.name === pluginName))
|
|
466
|
+
|
|
467
|
+
// when adapter is set, we can ignore the depends on plugin-oas, in v5 this will not be needed anymore
|
|
468
|
+
if (missingPlugins.includes('plugin-oas') && this.adapter) {
|
|
469
|
+
missingPlugins = missingPlugins.filter((pluginName) => pluginName !== 'plugin-oas')
|
|
470
|
+
}
|
|
460
471
|
|
|
461
472
|
if (missingPlugins.length > 0) {
|
|
462
473
|
throw new ValidationPluginError(`The plugin '${plugin.name}' has a pre set that references missing plugins for '${missingPlugins.join(', ')}'`)
|
|
@@ -476,41 +487,21 @@ export class PluginManager {
|
|
|
476
487
|
})
|
|
477
488
|
}
|
|
478
489
|
|
|
479
|
-
|
|
490
|
+
getPluginByName(pluginName: string): Plugin | undefined {
|
|
480
491
|
const plugins = [...this.#plugins]
|
|
481
|
-
const [searchPluginName] = pluginKey
|
|
482
492
|
|
|
483
|
-
return plugins.find((item) =>
|
|
484
|
-
const [name] = item.key
|
|
485
|
-
|
|
486
|
-
return name === searchPluginName
|
|
487
|
-
})
|
|
493
|
+
return plugins.find((item) => item.name === pluginName)
|
|
488
494
|
}
|
|
489
495
|
|
|
490
|
-
|
|
496
|
+
getPluginsByName(hookName: keyof PluginWithLifeCycle, pluginName: string): Plugin[] {
|
|
491
497
|
const plugins = [...this.plugins]
|
|
492
|
-
const [searchPluginName, searchIdentifier] = pluginKey
|
|
493
498
|
|
|
494
|
-
const pluginByPluginName = plugins
|
|
495
|
-
.filter((plugin) => hookName in plugin)
|
|
496
|
-
.filter((item) => {
|
|
497
|
-
const [name, identifier] = item.key
|
|
498
|
-
|
|
499
|
-
const identifierCheck = identifier?.toString() === searchIdentifier?.toString()
|
|
500
|
-
const nameCheck = name === searchPluginName
|
|
501
|
-
|
|
502
|
-
if (searchIdentifier) {
|
|
503
|
-
return identifierCheck && nameCheck
|
|
504
|
-
}
|
|
505
|
-
|
|
506
|
-
return nameCheck
|
|
507
|
-
})
|
|
499
|
+
const pluginByPluginName = plugins.filter((plugin) => hookName in plugin).filter((item) => item.name === pluginName)
|
|
508
500
|
|
|
509
501
|
if (!pluginByPluginName?.length) {
|
|
510
502
|
// fallback on the core plugin when there is no match
|
|
511
503
|
|
|
512
504
|
const corePlugin = plugins.find((plugin) => plugin.name === CORE_PLUGIN_NAME && hookName in plugin)
|
|
513
|
-
// Removed noisy debug logs for missing hooks - these are expected behavior, not errors
|
|
514
505
|
|
|
515
506
|
return corePlugin ? [corePlugin] : []
|
|
516
507
|
}
|
|
@@ -657,20 +648,16 @@ export class PluginManager {
|
|
|
657
648
|
|
|
658
649
|
setUniqueName(plugin.name, usedPluginNames)
|
|
659
650
|
|
|
660
|
-
// Emit warning if this is a duplicate plugin (will be removed in v5)
|
|
661
651
|
const usageCount = usedPluginNames[plugin.name]
|
|
662
652
|
if (usageCount && usageCount > 1) {
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
`Multiple instances of plugin "${plugin.name}" detected. This behavior is deprecated and will be removed in v5.`,
|
|
666
|
-
`Plugin key: [${plugin.name}, ${usageCount}]`,
|
|
653
|
+
throw new ValidationPluginError(
|
|
654
|
+
`Duplicate plugin "${plugin.name}" detected. Each plugin can only be used once. Use a different configuration instead of adding multiple instances of the same plugin.`,
|
|
667
655
|
)
|
|
668
656
|
}
|
|
669
657
|
|
|
670
658
|
return {
|
|
671
659
|
install() {},
|
|
672
660
|
...plugin,
|
|
673
|
-
key: [plugin.name, usedPluginNames[plugin.name]].filter(Boolean) as [typeof plugin.name, string],
|
|
674
661
|
} as unknown as Plugin
|
|
675
662
|
}
|
|
676
663
|
}
|