@kubb/core 4.34.0 → 4.35.0
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/hooks.d.ts +1 -1
- package/dist/index.cjs +143 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +22 -2
- package/dist/index.js +135 -9
- package/dist/index.js.map +1 -1
- package/dist/{types-DfjjJb2r.d.ts → types-7DgxNmCG.d.ts} +106 -2
- package/package.json +6 -4
- package/src/PluginManager.ts +35 -1
- package/src/build.ts +49 -2
- package/src/constants.ts +2 -0
- package/src/defineAdapter.ts +22 -0
- package/src/devtools.ts +59 -0
- package/src/index.ts +3 -0
- package/src/types.ts +101 -1
- package/src/utils/FunctionParams.ts +1 -0
|
@@ -2,6 +2,7 @@ import { t as __name } from "./chunk--u3MIqq1.js";
|
|
|
2
2
|
import { EventEmitter } from "node:events";
|
|
3
3
|
import { Fabric } from "@kubb/react-fabric";
|
|
4
4
|
import { KubbFile } from "@kubb/fabric-core/types";
|
|
5
|
+
import { Printer, RootNode } from "@kubb/ast/types";
|
|
5
6
|
|
|
6
7
|
//#region ../../internals/utils/dist/index.d.ts
|
|
7
8
|
/**
|
|
@@ -24,6 +25,7 @@ declare var AsyncEventEmitter: {
|
|
|
24
25
|
};
|
|
25
26
|
//#endregion
|
|
26
27
|
//#region src/constants.d.ts
|
|
28
|
+
declare const DEFAULT_STUDIO_URL: "https://studio.kubb.dev";
|
|
27
29
|
declare const logLevel: {
|
|
28
30
|
readonly silent: number;
|
|
29
31
|
readonly error: 0;
|
|
@@ -95,6 +97,11 @@ declare class PluginManager {
|
|
|
95
97
|
#private;
|
|
96
98
|
readonly config: Config;
|
|
97
99
|
readonly options: Options;
|
|
100
|
+
/**
|
|
101
|
+
* The universal `@kubb/ast` `RootNode` produced by the adapter, set by
|
|
102
|
+
* the build pipeline after the adapter's `parse()` resolves.
|
|
103
|
+
*/
|
|
104
|
+
rootNode: RootNode | undefined;
|
|
98
105
|
constructor(config: Config, options: Options);
|
|
99
106
|
get events(): AsyncEventEmitter<KubbEvents>;
|
|
100
107
|
getContext<TOptions extends PluginFactoryOptions>(plugin: Plugin<TOptions>): PluginContext<TOptions> & Record<string, unknown>;
|
|
@@ -437,7 +444,65 @@ type InputData = {
|
|
|
437
444
|
data: string | unknown;
|
|
438
445
|
};
|
|
439
446
|
type Input = InputPath | InputData | Array<InputPath>;
|
|
447
|
+
/**
|
|
448
|
+
* The raw source passed to an adapter's `parse` function.
|
|
449
|
+
* Mirrors the shape of `Config['input']` with paths already resolved to absolute.
|
|
450
|
+
*/
|
|
451
|
+
type AdapterSource = {
|
|
452
|
+
type: 'path';
|
|
453
|
+
path: string;
|
|
454
|
+
} | {
|
|
455
|
+
type: 'data';
|
|
456
|
+
data: string | unknown;
|
|
457
|
+
} | {
|
|
458
|
+
type: 'paths';
|
|
459
|
+
paths: Array<string>;
|
|
460
|
+
};
|
|
461
|
+
/**
|
|
462
|
+
* Type parameters for an adapter definition.
|
|
463
|
+
*
|
|
464
|
+
* Mirrors `PluginFactoryOptions` but scoped to the adapter lifecycle:
|
|
465
|
+
* - `TName` — unique string identifier (e.g. `'oas'`, `'asyncapi'`)
|
|
466
|
+
* - `TOptions` — raw user-facing options passed to the adapter factory
|
|
467
|
+
* - `TResolvedOptions` — defaults applied; what the adapter stores as `options`
|
|
468
|
+
*/
|
|
469
|
+
type AdapterFactoryOptions<TName extends string = string, TOptions extends object = object, TResolvedOptions extends object = TOptions> = {
|
|
470
|
+
name: TName;
|
|
471
|
+
options: TOptions;
|
|
472
|
+
resolvedOptions: TResolvedOptions;
|
|
473
|
+
};
|
|
474
|
+
/**
|
|
475
|
+
* An adapter converts a source file or data into a `@kubb/ast` `RootNode`.
|
|
476
|
+
*
|
|
477
|
+
* Adapters are the single entry-point for different schema formats
|
|
478
|
+
* (OpenAPI, AsyncAPI, Drizzle, …) and produce the universal `RootNode`
|
|
479
|
+
* that all Kubb plugins consume.
|
|
480
|
+
*
|
|
481
|
+
* @example
|
|
482
|
+
* ```ts
|
|
483
|
+
* import { oasAdapter } from '@kubb/adapter-oas'
|
|
484
|
+
*
|
|
485
|
+
* export default defineConfig({
|
|
486
|
+
* adapter: adapterOas(), // default — OpenAPI / Swagger
|
|
487
|
+
* input: { path: './openapi.yaml' },
|
|
488
|
+
* plugins: [pluginTs(), pluginZod()],
|
|
489
|
+
* })
|
|
490
|
+
* ```
|
|
491
|
+
*/
|
|
492
|
+
type Adapter<TOptions extends AdapterFactoryOptions = AdapterFactoryOptions> = {
|
|
493
|
+
/** Human-readable identifier, e.g. `'oas'`, `'drizzle'`, `'asyncapi'`. */name: TOptions['name']; /** Resolved options (after defaults have been applied). */
|
|
494
|
+
options: TOptions['resolvedOptions']; /** Convert the raw source into a universal `RootNode`. */
|
|
495
|
+
parse: (source: AdapterSource) => PossiblePromise<RootNode>;
|
|
496
|
+
};
|
|
440
497
|
type BarrelType = 'all' | 'named' | 'propagate';
|
|
498
|
+
type DevtoolsOptions = {
|
|
499
|
+
/**
|
|
500
|
+
* Open the AST inspector view (`/ast`) in Kubb Studio.
|
|
501
|
+
* When `false`, opens the main Studio page instead.
|
|
502
|
+
* @default false
|
|
503
|
+
*/
|
|
504
|
+
ast?: boolean;
|
|
505
|
+
};
|
|
441
506
|
/**
|
|
442
507
|
* @private
|
|
443
508
|
*/
|
|
@@ -451,6 +516,24 @@ type Config<TInput = Input> = {
|
|
|
451
516
|
* @default process.cwd()
|
|
452
517
|
*/
|
|
453
518
|
root: string;
|
|
519
|
+
/**
|
|
520
|
+
* Adapter that converts the input file into a `@kubb/ast` `RootNode` — the universal
|
|
521
|
+
* intermediate representation consumed by all Kubb plugins.
|
|
522
|
+
*
|
|
523
|
+
* - Omit (or pass `undefined`) to use the built-in OpenAPI/Swagger adapter.
|
|
524
|
+
* - Use `@kubb/adapter-oas` for explicit OpenAPI configuration (validate, contentType, …).
|
|
525
|
+
* - Use `@kubb/adapter-drizzle` or `@kubb/adapter-asyncapi` for other formats.
|
|
526
|
+
*
|
|
527
|
+
* @example
|
|
528
|
+
* ```ts
|
|
529
|
+
* import { drizzleAdapter } from '@kubb/adapter-drizzle'
|
|
530
|
+
* export default defineConfig({
|
|
531
|
+
* adapter: drizzleAdapter(),
|
|
532
|
+
* input: { path: './src/schema.ts' },
|
|
533
|
+
* })
|
|
534
|
+
* ```
|
|
535
|
+
*/
|
|
536
|
+
adapter?: Adapter;
|
|
454
537
|
/**
|
|
455
538
|
* You can use either `input.path` or `input.data`, depending on your specific needs.
|
|
456
539
|
*/
|
|
@@ -522,6 +605,16 @@ type Config<TInput = Input> = {
|
|
|
522
605
|
* If a plugin depends on another plugin, an error is returned if the required dependency is missing. See pre for more details.
|
|
523
606
|
*/
|
|
524
607
|
plugins?: Array<Plugin>;
|
|
608
|
+
/**
|
|
609
|
+
* Devtools configuration for Kubb Studio integration.
|
|
610
|
+
*/
|
|
611
|
+
devtools?: true | {
|
|
612
|
+
/**
|
|
613
|
+
* Override the Kubb Studio base URL.
|
|
614
|
+
* @default 'https://studio.kubb.dev'
|
|
615
|
+
*/
|
|
616
|
+
studioUrl?: typeof DEFAULT_STUDIO_URL | (string & {});
|
|
617
|
+
};
|
|
525
618
|
/**
|
|
526
619
|
* Hooks triggered when a specific action occurs in Kubb.
|
|
527
620
|
*/
|
|
@@ -684,6 +777,17 @@ type PluginContext<TOptions extends PluginFactoryOptions = PluginFactoryOptions>
|
|
|
684
777
|
* Current plugin
|
|
685
778
|
*/
|
|
686
779
|
plugin: Plugin<TOptions>;
|
|
780
|
+
/**
|
|
781
|
+
* Returns the universal `@kubb/ast` `RootNode` produced by the configured adapter.
|
|
782
|
+
* Returns `undefined` when no adapter was set (legacy OAS-only usage).
|
|
783
|
+
*/
|
|
784
|
+
rootNode: RootNode | undefined;
|
|
785
|
+
/**
|
|
786
|
+
* Opens the Kubb Studio URL for the current `rootNode` in the default browser.
|
|
787
|
+
* Falls back to printing the URL if the browser cannot be launched.
|
|
788
|
+
* No-ops silently when no adapter has set a `rootNode`.
|
|
789
|
+
*/
|
|
790
|
+
openInStudio: (options?: DevtoolsOptions) => Promise<void>;
|
|
687
791
|
} & Kubb.PluginContext;
|
|
688
792
|
/**
|
|
689
793
|
* Specify the export location for the files and define the behavior of the output
|
|
@@ -745,5 +849,5 @@ type Logger<TOptions extends LoggerOptions = LoggerOptions> = {
|
|
|
745
849
|
};
|
|
746
850
|
type UserLogger<TOptions extends LoggerOptions = LoggerOptions> = Omit<Logger<TOptions>, 'logLevel'>;
|
|
747
851
|
//#endregion
|
|
748
|
-
export {
|
|
749
|
-
//# sourceMappingURL=types-
|
|
852
|
+
export { UserPluginWithLifeCycle as A, Printer as C, UserConfig as D, UnknownUserPlugin as E, linters as F, logLevel as I, AsyncEventEmitter as L, PluginManager as M, getMode as N, UserLogger as O, formatters as P, PluginWithLifeCycle as S, ResolvePathParams as T, PluginFactoryOptions as _, Config as a, PluginLifecycleHooks as b, Group as c, Logger as d, LoggerContext as f, PluginContext as g, Plugin as h, BarrelType as i, KubbEvents as j, UserPlugin as k, InputData as l, Output as m, AdapterFactoryOptions as n, DevtoolsOptions as o, LoggerOptions as p, AdapterSource as r, GetPluginFactoryOptions as s, Adapter as t, InputPath as u, PluginKey as v, ResolveNameParams as w, PluginParameter as x, PluginLifecycle as y };
|
|
853
|
+
//# sourceMappingURL=types-7DgxNmCG.d.ts.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kubb/core",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.35.0",
|
|
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",
|
|
@@ -67,9 +67,11 @@
|
|
|
67
67
|
"@kubb/fabric-core": "0.13.3",
|
|
68
68
|
"@kubb/react-fabric": "0.13.3",
|
|
69
69
|
"empathic": "^2.0.0",
|
|
70
|
+
"fflate": "^0.8.2",
|
|
70
71
|
"remeda": "^2.33.6",
|
|
71
72
|
"semver": "^7.7.4",
|
|
72
|
-
"tinyexec": "^1.0.
|
|
73
|
+
"tinyexec": "^1.0.4",
|
|
74
|
+
"@kubb/ast": "4.35.0"
|
|
73
75
|
},
|
|
74
76
|
"devDependencies": {
|
|
75
77
|
"@types/semver": "^7.7.1",
|
|
@@ -90,8 +92,8 @@
|
|
|
90
92
|
"main": "./dist/index.cjs",
|
|
91
93
|
"module": "./dist/index.js",
|
|
92
94
|
"inlinedDependencies": {
|
|
93
|
-
"
|
|
94
|
-
"
|
|
95
|
+
"p-limit": "7.3.0",
|
|
96
|
+
"yocto-queue": "1.2.2"
|
|
95
97
|
},
|
|
96
98
|
"scripts": {
|
|
97
99
|
"build": "tsdown && size-limit",
|
package/src/PluginManager.ts
CHANGED
|
@@ -2,13 +2,16 @@ import path from 'node:path'
|
|
|
2
2
|
import { performance } from 'node:perf_hooks'
|
|
3
3
|
import type { AsyncEventEmitter } from '@internals/utils'
|
|
4
4
|
import { setUniqueName, transformReservedWord } from '@internals/utils'
|
|
5
|
+
import type { RootNode } from '@kubb/ast/types'
|
|
5
6
|
import type { KubbFile } from '@kubb/fabric-core/types'
|
|
6
7
|
import type { Fabric } from '@kubb/react-fabric'
|
|
7
|
-
import { CORE_PLUGIN_NAME } from './constants.ts'
|
|
8
|
+
import { CORE_PLUGIN_NAME, DEFAULT_STUDIO_URL } from './constants.ts'
|
|
9
|
+
import { openInStudio as openInStudioFn } from './devtools.ts'
|
|
8
10
|
import { ValidationPluginError } from './errors.ts'
|
|
9
11
|
import { isPromiseRejectedResult, PromiseManager } from './PromiseManager.ts'
|
|
10
12
|
import type {
|
|
11
13
|
Config,
|
|
14
|
+
DevtoolsOptions,
|
|
12
15
|
KubbEvents,
|
|
13
16
|
Plugin,
|
|
14
17
|
PluginContext,
|
|
@@ -63,6 +66,13 @@ export class PluginManager {
|
|
|
63
66
|
readonly config: Config
|
|
64
67
|
readonly options: Options
|
|
65
68
|
|
|
69
|
+
/**
|
|
70
|
+
* The universal `@kubb/ast` `RootNode` produced by the adapter, set by
|
|
71
|
+
* the build pipeline after the adapter's `parse()` resolves.
|
|
72
|
+
*/
|
|
73
|
+
rootNode: RootNode | undefined = undefined
|
|
74
|
+
#studioIsOpen = false
|
|
75
|
+
|
|
66
76
|
readonly #plugins = new Set<Plugin>()
|
|
67
77
|
readonly #usedPluginNames: Record<string, number> = {}
|
|
68
78
|
readonly #promiseManager
|
|
@@ -86,6 +96,8 @@ export class PluginManager {
|
|
|
86
96
|
|
|
87
97
|
getContext<TOptions extends PluginFactoryOptions>(plugin: Plugin<TOptions>): PluginContext<TOptions> & Record<string, unknown> {
|
|
88
98
|
const plugins = [...this.#plugins]
|
|
99
|
+
const pluginManager = this
|
|
100
|
+
|
|
89
101
|
const baseContext = {
|
|
90
102
|
fabric: this.options.fabric,
|
|
91
103
|
config: this.config,
|
|
@@ -99,6 +111,28 @@ export class PluginManager {
|
|
|
99
111
|
upsertFile: async (...files: Array<KubbFile.File>) => {
|
|
100
112
|
await this.options.fabric.upsertFile(...files)
|
|
101
113
|
},
|
|
114
|
+
get rootNode(): RootNode | undefined {
|
|
115
|
+
return pluginManager.rootNode
|
|
116
|
+
},
|
|
117
|
+
openInStudio(options?: DevtoolsOptions) {
|
|
118
|
+
if (typeof pluginManager.config.devtools !== 'object') {
|
|
119
|
+
throw new Error('Devtools must be an object')
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if (!pluginManager.rootNode) {
|
|
123
|
+
throw new Error('RootNode is not defined, make sure you have set the parser in kubb.config.ts')
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (pluginManager.#studioIsOpen) {
|
|
127
|
+
return
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
pluginManager.#studioIsOpen = true
|
|
131
|
+
|
|
132
|
+
const studioUrl = pluginManager.config.devtools?.studioUrl ?? DEFAULT_STUDIO_URL
|
|
133
|
+
|
|
134
|
+
return openInStudioFn(pluginManager.rootNode, studioUrl, options)
|
|
135
|
+
},
|
|
102
136
|
} as unknown as PluginContext<TOptions>
|
|
103
137
|
|
|
104
138
|
const mergedExtras: Record<string, unknown> = {}
|
package/src/build.ts
CHANGED
|
@@ -6,10 +6,10 @@ import { createFabric } from '@kubb/react-fabric'
|
|
|
6
6
|
import { typescriptParser } from '@kubb/react-fabric/parsers'
|
|
7
7
|
import { fsPlugin } from '@kubb/react-fabric/plugins'
|
|
8
8
|
import { isInputPath } from './config.ts'
|
|
9
|
-
import { BARREL_FILENAME, DEFAULT_BANNER, DEFAULT_CONCURRENCY, DEFAULT_EXTENSION } from './constants.ts'
|
|
9
|
+
import { BARREL_FILENAME, DEFAULT_BANNER, DEFAULT_CONCURRENCY, DEFAULT_EXTENSION, DEFAULT_STUDIO_URL } from './constants.ts'
|
|
10
10
|
import { BuildError } from './errors.ts'
|
|
11
11
|
import { PluginManager } from './PluginManager.ts'
|
|
12
|
-
import type { Config, KubbEvents, Output, Plugin, UserConfig } from './types.ts'
|
|
12
|
+
import type { AdapterSource, Config, KubbEvents, Output, Plugin, UserConfig } from './types.ts'
|
|
13
13
|
import { getDiagnosticInfo } from './utils/diagnostics.ts'
|
|
14
14
|
import type { FileMetaBase } from './utils/getBarrelFiles.ts'
|
|
15
15
|
|
|
@@ -96,6 +96,12 @@ export async function setup(options: BuildOptions): Promise<SetupResult> {
|
|
|
96
96
|
defaultBanner: DEFAULT_BANNER,
|
|
97
97
|
...userConfig.output,
|
|
98
98
|
},
|
|
99
|
+
devtools: userConfig.devtools
|
|
100
|
+
? {
|
|
101
|
+
studioUrl: DEFAULT_STUDIO_URL,
|
|
102
|
+
...(typeof userConfig.devtools === 'boolean' ? {} : userConfig.devtools),
|
|
103
|
+
}
|
|
104
|
+
: undefined,
|
|
99
105
|
plugins: userConfig.plugins as Config['plugins'],
|
|
100
106
|
}
|
|
101
107
|
|
|
@@ -159,6 +165,27 @@ export async function setup(options: BuildOptions): Promise<SetupResult> {
|
|
|
159
165
|
concurrency: DEFAULT_CONCURRENCY,
|
|
160
166
|
})
|
|
161
167
|
|
|
168
|
+
// Run the adapter (if provided) to produce the universal RootNode
|
|
169
|
+
if (definedConfig.adapter) {
|
|
170
|
+
const source = inputToAdapterSource(definedConfig)
|
|
171
|
+
|
|
172
|
+
await events.emit('debug', {
|
|
173
|
+
date: new Date(),
|
|
174
|
+
logs: [`Running adapter: ${definedConfig.adapter.name}`],
|
|
175
|
+
})
|
|
176
|
+
|
|
177
|
+
pluginManager.rootNode = await definedConfig.adapter.parse(source)
|
|
178
|
+
|
|
179
|
+
await events.emit('debug', {
|
|
180
|
+
date: new Date(),
|
|
181
|
+
logs: [
|
|
182
|
+
`✓ Adapter '${definedConfig.adapter.name}' resolved RootNode`,
|
|
183
|
+
` • Schemas: ${pluginManager.rootNode.schemas.length}`,
|
|
184
|
+
` • Operations: ${pluginManager.rootNode.operations.length}`,
|
|
185
|
+
],
|
|
186
|
+
})
|
|
187
|
+
}
|
|
188
|
+
|
|
162
189
|
return {
|
|
163
190
|
events,
|
|
164
191
|
fabric,
|
|
@@ -364,3 +391,23 @@ function buildBarrelExports({ barrelFiles, rootDir, existingExports, config, plu
|
|
|
364
391
|
})
|
|
365
392
|
})
|
|
366
393
|
}
|
|
394
|
+
|
|
395
|
+
/**
|
|
396
|
+
* Maps the resolved `Config['input']` shape into an `AdapterSource` that
|
|
397
|
+
* the adapter's `parse()` can consume.
|
|
398
|
+
*/
|
|
399
|
+
function inputToAdapterSource(config: Config): AdapterSource {
|
|
400
|
+
if (Array.isArray(config.input)) {
|
|
401
|
+
return {
|
|
402
|
+
type: 'paths',
|
|
403
|
+
paths: config.input.map((i) => resolve(config.root, i.path)),
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
if ('data' in config.input) {
|
|
408
|
+
return { type: 'data', data: config.input.data }
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
const resolved = resolve(config.root, config.input.path)
|
|
412
|
+
return { type: 'path', path: resolved }
|
|
413
|
+
}
|
package/src/constants.ts
CHANGED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { Adapter, AdapterFactoryOptions } from './types.ts'
|
|
2
|
+
|
|
3
|
+
type AdapterBuilder<T extends AdapterFactoryOptions> = (options: T['options']) => Adapter<T>
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Wraps an adapter builder to make the options parameter optional.
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* export const adapterOas = defineAdapter<OasAdapter>((options) => {
|
|
11
|
+
* const { validate = true, dateType = 'string' } = options
|
|
12
|
+
* return {
|
|
13
|
+
* name: adapterOasName,
|
|
14
|
+
* options: { validate, dateType, ... },
|
|
15
|
+
* parse(source) { ... },
|
|
16
|
+
* }
|
|
17
|
+
* })
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
export function defineAdapter<T extends AdapterFactoryOptions = AdapterFactoryOptions>(build: AdapterBuilder<T>): (options?: T['options']) => Adapter<T> {
|
|
21
|
+
return (options) => build(options ?? ({} as T['options']))
|
|
22
|
+
}
|
package/src/devtools.ts
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { RootNode } from '@kubb/ast/types'
|
|
2
|
+
import { deflateSync, inflateSync } from 'fflate'
|
|
3
|
+
import { x } from 'tinyexec'
|
|
4
|
+
import type { DevtoolsOptions } from './types.ts'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Encodes a `RootNode` as a compressed, URL-safe string.
|
|
8
|
+
*
|
|
9
|
+
* The JSON representation is deflate-compressed with {@link deflateSync} before
|
|
10
|
+
* base64url encoding, which typically reduces payload size by 70–80 % and
|
|
11
|
+
* keeps URLs well within browser and server path-length limits.
|
|
12
|
+
*
|
|
13
|
+
* Use {@link decodeAst} to reverse.
|
|
14
|
+
*/
|
|
15
|
+
export function encodeAst(root: RootNode): string {
|
|
16
|
+
const compressed = deflateSync(new TextEncoder().encode(JSON.stringify(root)))
|
|
17
|
+
return Buffer.from(compressed).toString('base64url')
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Decodes a `RootNode` from a string produced by {@link encodeAst}.
|
|
22
|
+
*
|
|
23
|
+
* Works in both Node.js and the browser — no streaming APIs required.
|
|
24
|
+
*/
|
|
25
|
+
export function decodeAst(encoded: string): RootNode {
|
|
26
|
+
const bytes = Buffer.from(encoded, 'base64url')
|
|
27
|
+
return JSON.parse(new TextDecoder().decode(inflateSync(bytes))) as RootNode
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Constructs the Kubb Studio URL for the given `RootNode`.
|
|
32
|
+
* When `options.ast` is `true`, navigates to the AST inspector (`/ast`).
|
|
33
|
+
* The `root` is encoded and attached as the `?root=` query parameter so Studio
|
|
34
|
+
* can decode and render it without a round-trip to any server.
|
|
35
|
+
*/
|
|
36
|
+
export function getStudioUrl(root: RootNode, studioUrl: string, options: DevtoolsOptions = {}): string {
|
|
37
|
+
const baseUrl = studioUrl.replace(/\/$/, '')
|
|
38
|
+
const path = options.ast ? '/ast' : ''
|
|
39
|
+
|
|
40
|
+
return `${baseUrl}${path}?root=${encodeAst(root)}`
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Opens the Kubb Studio URL for the given `RootNode` in the default browser —
|
|
45
|
+
*
|
|
46
|
+
* Falls back to printing the URL if the browser cannot be launched.
|
|
47
|
+
*/
|
|
48
|
+
export async function openInStudio(root: RootNode, studioUrl: string, options: DevtoolsOptions = {}): Promise<void> {
|
|
49
|
+
const url = getStudioUrl(root, studioUrl, options)
|
|
50
|
+
|
|
51
|
+
const cmd = process.platform === 'win32' ? 'cmd' : process.platform === 'darwin' ? 'open' : 'xdg-open'
|
|
52
|
+
const args = process.platform === 'win32' ? ['/c', 'start', '', url] : [url]
|
|
53
|
+
|
|
54
|
+
try {
|
|
55
|
+
await x(cmd, args)
|
|
56
|
+
} catch {
|
|
57
|
+
console.log(`\n ${url}\n`)
|
|
58
|
+
}
|
|
59
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
|
+
export { AsyncEventEmitter } from '@internals/utils'
|
|
2
|
+
export { definePrinter } from '@kubb/ast'
|
|
1
3
|
export { build, build as default, safeBuild, setup } from './build.ts'
|
|
2
4
|
export { type CLIOptions, type ConfigInput, defineConfig, isInputPath } from './config.ts'
|
|
3
5
|
export { formatters, linters, logLevel } from './constants.ts'
|
|
6
|
+
export { defineAdapter } from './defineAdapter.ts'
|
|
4
7
|
export { defineLogger } from './defineLogger.ts'
|
|
5
8
|
export { definePlugin } from './definePlugin.ts'
|
|
6
9
|
export { PackageManager } from './PackageManager.ts'
|
package/src/types.ts
CHANGED
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
import type { AsyncEventEmitter, PossiblePromise } from '@internals/utils'
|
|
2
|
+
import type { RootNode } from '@kubb/ast/types'
|
|
2
3
|
import type { KubbFile } from '@kubb/fabric-core/types'
|
|
3
4
|
import type { Fabric } from '@kubb/react-fabric'
|
|
4
|
-
import type { logLevel } from './constants.ts'
|
|
5
|
+
import type { DEFAULT_STUDIO_URL, logLevel } from './constants.ts'
|
|
5
6
|
import type { KubbEvents } from './Kubb.ts'
|
|
6
7
|
import type { PluginManager } from './PluginManager.ts'
|
|
7
8
|
|
|
9
|
+
export type { Printer } from '@kubb/ast/types'
|
|
10
|
+
|
|
8
11
|
declare global {
|
|
9
12
|
namespace Kubb {
|
|
10
13
|
interface PluginContext {}
|
|
@@ -49,8 +52,64 @@ export type InputData = {
|
|
|
49
52
|
|
|
50
53
|
type Input = InputPath | InputData | Array<InputPath>
|
|
51
54
|
|
|
55
|
+
/**
|
|
56
|
+
* The raw source passed to an adapter's `parse` function.
|
|
57
|
+
* Mirrors the shape of `Config['input']` with paths already resolved to absolute.
|
|
58
|
+
*/
|
|
59
|
+
export type AdapterSource = { type: 'path'; path: string } | { type: 'data'; data: string | unknown } | { type: 'paths'; paths: Array<string> }
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Type parameters for an adapter definition.
|
|
63
|
+
*
|
|
64
|
+
* Mirrors `PluginFactoryOptions` but scoped to the adapter lifecycle:
|
|
65
|
+
* - `TName` — unique string identifier (e.g. `'oas'`, `'asyncapi'`)
|
|
66
|
+
* - `TOptions` — raw user-facing options passed to the adapter factory
|
|
67
|
+
* - `TResolvedOptions` — defaults applied; what the adapter stores as `options`
|
|
68
|
+
*/
|
|
69
|
+
export type AdapterFactoryOptions<TName extends string = string, TOptions extends object = object, TResolvedOptions extends object = TOptions> = {
|
|
70
|
+
name: TName
|
|
71
|
+
options: TOptions
|
|
72
|
+
resolvedOptions: TResolvedOptions
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* An adapter converts a source file or data into a `@kubb/ast` `RootNode`.
|
|
77
|
+
*
|
|
78
|
+
* Adapters are the single entry-point for different schema formats
|
|
79
|
+
* (OpenAPI, AsyncAPI, Drizzle, …) and produce the universal `RootNode`
|
|
80
|
+
* that all Kubb plugins consume.
|
|
81
|
+
*
|
|
82
|
+
* @example
|
|
83
|
+
* ```ts
|
|
84
|
+
* import { oasAdapter } from '@kubb/adapter-oas'
|
|
85
|
+
*
|
|
86
|
+
* export default defineConfig({
|
|
87
|
+
* adapter: adapterOas(), // default — OpenAPI / Swagger
|
|
88
|
+
* input: { path: './openapi.yaml' },
|
|
89
|
+
* plugins: [pluginTs(), pluginZod()],
|
|
90
|
+
* })
|
|
91
|
+
* ```
|
|
92
|
+
*/
|
|
93
|
+
export type Adapter<TOptions extends AdapterFactoryOptions = AdapterFactoryOptions> = {
|
|
94
|
+
/** Human-readable identifier, e.g. `'oas'`, `'drizzle'`, `'asyncapi'`. */
|
|
95
|
+
name: TOptions['name']
|
|
96
|
+
/** Resolved options (after defaults have been applied). */
|
|
97
|
+
options: TOptions['resolvedOptions']
|
|
98
|
+
/** Convert the raw source into a universal `RootNode`. */
|
|
99
|
+
parse: (source: AdapterSource) => PossiblePromise<RootNode>
|
|
100
|
+
}
|
|
101
|
+
|
|
52
102
|
export type BarrelType = 'all' | 'named' | 'propagate'
|
|
53
103
|
|
|
104
|
+
export type DevtoolsOptions = {
|
|
105
|
+
/**
|
|
106
|
+
* Open the AST inspector view (`/ast`) in Kubb Studio.
|
|
107
|
+
* When `false`, opens the main Studio page instead.
|
|
108
|
+
* @default false
|
|
109
|
+
*/
|
|
110
|
+
ast?: boolean
|
|
111
|
+
}
|
|
112
|
+
|
|
54
113
|
/**
|
|
55
114
|
* @private
|
|
56
115
|
*/
|
|
@@ -64,6 +123,24 @@ export type Config<TInput = Input> = {
|
|
|
64
123
|
* @default process.cwd()
|
|
65
124
|
*/
|
|
66
125
|
root: string
|
|
126
|
+
/**
|
|
127
|
+
* Adapter that converts the input file into a `@kubb/ast` `RootNode` — the universal
|
|
128
|
+
* intermediate representation consumed by all Kubb plugins.
|
|
129
|
+
*
|
|
130
|
+
* - Omit (or pass `undefined`) to use the built-in OpenAPI/Swagger adapter.
|
|
131
|
+
* - Use `@kubb/adapter-oas` for explicit OpenAPI configuration (validate, contentType, …).
|
|
132
|
+
* - Use `@kubb/adapter-drizzle` or `@kubb/adapter-asyncapi` for other formats.
|
|
133
|
+
*
|
|
134
|
+
* @example
|
|
135
|
+
* ```ts
|
|
136
|
+
* import { drizzleAdapter } from '@kubb/adapter-drizzle'
|
|
137
|
+
* export default defineConfig({
|
|
138
|
+
* adapter: drizzleAdapter(),
|
|
139
|
+
* input: { path: './src/schema.ts' },
|
|
140
|
+
* })
|
|
141
|
+
* ```
|
|
142
|
+
*/
|
|
143
|
+
adapter?: Adapter
|
|
67
144
|
/**
|
|
68
145
|
* You can use either `input.path` or `input.data`, depending on your specific needs.
|
|
69
146
|
*/
|
|
@@ -135,6 +212,18 @@ export type Config<TInput = Input> = {
|
|
|
135
212
|
* If a plugin depends on another plugin, an error is returned if the required dependency is missing. See pre for more details.
|
|
136
213
|
*/
|
|
137
214
|
plugins?: Array<Plugin>
|
|
215
|
+
/**
|
|
216
|
+
* Devtools configuration for Kubb Studio integration.
|
|
217
|
+
*/
|
|
218
|
+
devtools?:
|
|
219
|
+
| true
|
|
220
|
+
| {
|
|
221
|
+
/**
|
|
222
|
+
* Override the Kubb Studio base URL.
|
|
223
|
+
* @default 'https://studio.kubb.dev'
|
|
224
|
+
*/
|
|
225
|
+
studioUrl?: typeof DEFAULT_STUDIO_URL | (string & {})
|
|
226
|
+
}
|
|
138
227
|
/**
|
|
139
228
|
* Hooks triggered when a specific action occurs in Kubb.
|
|
140
229
|
*/
|
|
@@ -315,6 +404,17 @@ export type PluginContext<TOptions extends PluginFactoryOptions = PluginFactoryO
|
|
|
315
404
|
* Current plugin
|
|
316
405
|
*/
|
|
317
406
|
plugin: Plugin<TOptions>
|
|
407
|
+
/**
|
|
408
|
+
* Returns the universal `@kubb/ast` `RootNode` produced by the configured adapter.
|
|
409
|
+
* Returns `undefined` when no adapter was set (legacy OAS-only usage).
|
|
410
|
+
*/
|
|
411
|
+
rootNode: RootNode | undefined
|
|
412
|
+
/**
|
|
413
|
+
* Opens the Kubb Studio URL for the current `rootNode` in the default browser.
|
|
414
|
+
* Falls back to printing the URL if the browser cannot be launched.
|
|
415
|
+
* No-ops silently when no adapter has set a `rootNode`.
|
|
416
|
+
*/
|
|
417
|
+
openInStudio: (options?: DevtoolsOptions) => Promise<void>
|
|
318
418
|
} & Kubb.PluginContext
|
|
319
419
|
/**
|
|
320
420
|
* Specify the export location for the files and define the behavior of the output
|