@kubb/core 5.0.0-alpha.20 → 5.0.0-alpha.22

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.js CHANGED
@@ -965,6 +965,15 @@ function hookParallel(promises, concurrency = Number.POSITIVE_INFINITY) {
965
965
  }
966
966
  //#endregion
967
967
  //#region src/PluginDriver.ts
968
+ /**
969
+ * Returns `'single'` when `fileOrFolder` has a file extension, `'split'` otherwise.
970
+ *
971
+ * @example
972
+ * ```ts
973
+ * getMode('src/gen/types.ts') // 'single'
974
+ * getMode('src/gen/types') // 'split'
975
+ * ```
976
+ */
968
977
  function getMode(fileOrFolder) {
969
978
  if (!fileOrFolder) return "split";
970
979
  return extname(fileOrFolder) ? "single" : "split";
@@ -1463,7 +1472,7 @@ const fsStorage = createStorage(() => ({
1463
1472
  }));
1464
1473
  //#endregion
1465
1474
  //#region package.json
1466
- var version$1 = "5.0.0-alpha.20";
1475
+ var version$1 = "5.0.0-alpha.22";
1467
1476
  //#endregion
1468
1477
  //#region src/utils/diagnostics.ts
1469
1478
  /**
@@ -1851,6 +1860,26 @@ function createPlugin(build) {
1851
1860
  return (options) => build(options ?? {});
1852
1861
  }
1853
1862
  //#endregion
1863
+ //#region src/defineBuilder.ts
1864
+ /**
1865
+ * Defines a builder for a plugin — a named collection of schema-building helpers that
1866
+ * can be exported alongside the plugin and imported by other plugins or generators.
1867
+ *
1868
+ * @example
1869
+ * export const builder = defineBuilder<PluginTs>(() => ({
1870
+ * name: 'default',
1871
+ * buildParamsSchema({ params, node, resolver }) {
1872
+ * return createSchema({ type: 'object', properties: [] })
1873
+ * },
1874
+ * buildDataSchemaNode({ node, resolver }) {
1875
+ * return createSchema({ type: 'object', properties: [] })
1876
+ * },
1877
+ * }))
1878
+ */
1879
+ function defineBuilder(build) {
1880
+ return build();
1881
+ }
1882
+ //#endregion
1854
1883
  //#region src/defineGenerator.ts
1855
1884
  function defineGenerator(generator) {
1856
1885
  if (generator.type === "react") return {
@@ -1900,8 +1929,8 @@ function defineLogger(logger) {
1900
1929
  //#endregion
1901
1930
  //#region src/definePreset.ts
1902
1931
  /**
1903
- * Creates a typed preset object that bundles a name, resolvers, and optional
1904
- * transformers — the building block for composable plugin presets.
1932
+ * Creates a typed preset object that bundles a name, resolvers, optional
1933
+ * transformers, and optional generators — the building block for composable plugin presets.
1905
1934
  *
1906
1935
  * @example
1907
1936
  * import { definePreset } from '@kubb/core'
@@ -1912,12 +1941,17 @@ function defineLogger(logger) {
1912
1941
  * @example
1913
1942
  * // With custom transformers
1914
1943
  * export const myPreset = definePreset('myPreset', { resolvers: [resolverTsLegacy], transformers: [myTransformer] })
1944
+ *
1945
+ * @example
1946
+ * // With generators
1947
+ * export const myPreset = definePreset('myPreset', { resolvers: [resolverTsLegacy], generators: [typeGeneratorLegacy] })
1915
1948
  */
1916
- function definePreset(name, { resolvers, transformers }) {
1949
+ function definePreset(name, { resolvers, transformers, generators }) {
1917
1950
  return {
1918
1951
  name,
1919
1952
  resolvers,
1920
- transformers
1953
+ transformers,
1954
+ generators
1921
1955
  };
1922
1956
  }
1923
1957
  //#endregion
@@ -1952,6 +1986,7 @@ function matchesOperationPattern(node, type, pattern) {
1952
1986
  }
1953
1987
  /**
1954
1988
  * Checks if a schema matches a pattern for a given filter type (`schemaName`).
1989
+ *
1955
1990
  * Returns `null` when the filter type doesn't apply to schemas.
1956
1991
  */
1957
1992
  function matchesSchemaPattern(node, type, pattern) {
@@ -1961,7 +1996,11 @@ function matchesSchemaPattern(node, type, pattern) {
1961
1996
  }
1962
1997
  }
1963
1998
  /**
1964
- * Default name resolver `camelCase` for most types, `PascalCase` for `type`.
1999
+ * Default name resolver used by `defineResolver`.
2000
+ *
2001
+ * - `camelCase` for `function` and `file` types.
2002
+ * - `PascalCase` for `type`.
2003
+ * - `camelCase` for everything else.
1965
2004
  */
1966
2005
  function defaultResolver(name, type) {
1967
2006
  let resolvedName = camelCase(name);
@@ -1970,8 +2009,27 @@ function defaultResolver(name, type) {
1970
2009
  return resolvedName;
1971
2010
  }
1972
2011
  /**
1973
- * Default option resolver — applies include/exclude filters and merges any matching override options.
1974
- * Returns `null` when the node is filtered out.
2012
+ * Default option resolver — applies include/exclude filters and merges matching override options.
2013
+ *
2014
+ * Returns `null` when the node is filtered out by an `exclude` rule or not matched by any `include` rule.
2015
+ *
2016
+ * @example Include/exclude filtering
2017
+ * ```ts
2018
+ * const options = defaultResolveOptions(operationNode, {
2019
+ * options: { output: 'types' },
2020
+ * exclude: [{ type: 'tag', pattern: 'internal' }],
2021
+ * })
2022
+ * // → null when node has tag 'internal'
2023
+ * ```
2024
+ *
2025
+ * @example Override merging
2026
+ * ```ts
2027
+ * const options = defaultResolveOptions(operationNode, {
2028
+ * options: { enumType: 'asConst' },
2029
+ * override: [{ type: 'operationId', pattern: 'listPets', options: { enumType: 'enum' } }],
2030
+ * })
2031
+ * // → { enumType: 'enum' } when operationId matches
2032
+ * ```
1975
2033
  */
1976
2034
  function defaultResolveOptions(node, { options, exclude = [], include, override = [] }) {
1977
2035
  if (isOperationNode(node)) {
@@ -1998,27 +2056,245 @@ function defaultResolveOptions(node, { options, exclude = [], include, override
1998
2056
  return options;
1999
2057
  }
2000
2058
  /**
2001
- * Defines a resolver for a plugin, with built-in defaults for name casing and include/exclude/override filtering.
2002
- * Override `default` or `resolveOptions` in the builder to customize the behavior.
2059
+ * Default path resolver used by `defineResolver`.
2003
2060
  *
2004
- * @example
2061
+ * - Returns the output directory in `single` mode.
2062
+ * - Resolves into a tag- or path-based subdirectory when `group` and a `tag`/`path` value are provided.
2063
+ * - Falls back to a flat `output/baseName` path otherwise.
2064
+ *
2065
+ * A custom `group.name` function overrides the default subdirectory naming.
2066
+ * For `tag` groups the default is `${camelCase(tag)}Controller`.
2067
+ * For `path` groups the default is the first path segment after `/`.
2068
+ *
2069
+ * @example Flat output
2070
+ * ```ts
2071
+ * defaultResolvePath({ baseName: 'petTypes.ts' }, { root: '/src', output: { path: 'types' } })
2072
+ * // → '/src/types/petTypes.ts'
2073
+ * ```
2074
+ *
2075
+ * @example Tag-based grouping
2076
+ * ```ts
2077
+ * defaultResolvePath(
2078
+ * { baseName: 'petTypes.ts', tag: 'pets' },
2079
+ * { root: '/src', output: { path: 'types' }, group: { type: 'tag' } },
2080
+ * )
2081
+ * // → '/src/types/petsController/petTypes.ts'
2082
+ * ```
2083
+ *
2084
+ * @example Path-based grouping
2085
+ * ```ts
2086
+ * defaultResolvePath(
2087
+ * { baseName: 'petTypes.ts', path: '/pets/list' },
2088
+ * { root: '/src', output: { path: 'types' }, group: { type: 'path' } },
2089
+ * )
2090
+ * // → '/src/types/pets/petTypes.ts'
2091
+ * ```
2092
+ *
2093
+ * @example Single-file mode
2094
+ * ```ts
2095
+ * defaultResolvePath(
2096
+ * { baseName: 'petTypes.ts', pathMode: 'single' },
2097
+ * { root: '/src', output: { path: 'types' } },
2098
+ * )
2099
+ * // → '/src/types'
2100
+ * ```
2101
+ */
2102
+ function defaultResolvePath({ baseName, pathMode, tag, path: groupPath }, { root, output, group }) {
2103
+ if ((pathMode ?? getMode(path.resolve(root, output.path))) === "single") return path.resolve(root, output.path);
2104
+ if (group && (groupPath || tag)) {
2105
+ const groupName = group.name ? group.name : (ctx) => {
2106
+ if (group.type === "path") return `${ctx.group.split("/")[1]}`;
2107
+ return `${camelCase(ctx.group)}Controller`;
2108
+ };
2109
+ return path.resolve(root, output.path, groupName({ group: group.type === "path" ? groupPath : tag }), baseName);
2110
+ }
2111
+ return path.resolve(root, output.path, baseName);
2112
+ }
2113
+ /**
2114
+ * Default file resolver used by `defineResolver`.
2115
+ *
2116
+ * Resolves a `FabricFile.File` by combining name resolution (`resolver.default`) with
2117
+ * path resolution (`resolver.resolvePath`). The resolved file always has empty
2118
+ * `sources`, `imports`, and `exports` arrays — consumers populate those separately.
2119
+ *
2120
+ * In `single` mode the name is omitted and the file sits directly in the output directory.
2121
+ *
2122
+ * @example Resolve a schema file
2123
+ * ```ts
2124
+ * const file = defaultResolveFile.call(resolver,
2125
+ * { name: 'pet', extname: '.ts' },
2126
+ * { root: '/src', output: { path: 'types' } },
2127
+ * )
2128
+ * // → { baseName: 'pet.ts', path: '/src/types/pet.ts', sources: [], ... }
2129
+ * ```
2130
+ *
2131
+ * @example Resolve an operation file with tag grouping
2132
+ * ```ts
2133
+ * const file = defaultResolveFile.call(resolver,
2134
+ * { name: 'listPets', extname: '.ts', tag: 'pets' },
2135
+ * { root: '/src', output: { path: 'types' }, group: { type: 'tag' } },
2136
+ * )
2137
+ * // → { baseName: 'listPets.ts', path: '/src/types/petsController/listPets.ts', ... }
2138
+ * ```
2139
+ */
2140
+ function defaultResolveFile({ name, extname, tag, path: groupPath }, context) {
2141
+ const pathMode = getMode(path.resolve(context.root, context.output.path));
2142
+ const baseName = `${pathMode === "single" ? "" : this.default(name, "file")}${extname}`;
2143
+ const filePath = this.resolvePath({
2144
+ baseName,
2145
+ pathMode,
2146
+ tag,
2147
+ path: groupPath
2148
+ }, context);
2149
+ return {
2150
+ path: filePath,
2151
+ baseName: path.basename(filePath),
2152
+ meta: { pluginName: this.pluginName },
2153
+ sources: [],
2154
+ imports: [],
2155
+ exports: []
2156
+ };
2157
+ }
2158
+ /**
2159
+ * Generates the default "Generated by Kubb" banner from config and optional node metadata.
2160
+ */
2161
+ function buildDefaultBanner({ title, description, version, config }) {
2162
+ try {
2163
+ let source = "";
2164
+ if (Array.isArray(config.input)) {
2165
+ const first = config.input[0];
2166
+ if (first && "path" in first) source = path.basename(first.path);
2167
+ } else if ("path" in config.input) source = path.basename(config.input.path);
2168
+ else if ("data" in config.input) source = "text content";
2169
+ let banner = "/**\n* Generated by Kubb (https://kubb.dev/).\n* Do not edit manually.\n";
2170
+ if (config.output.defaultBanner === "simple") {
2171
+ banner += "*/\n";
2172
+ return banner;
2173
+ }
2174
+ if (source) banner += `* Source: ${source}\n`;
2175
+ if (title) banner += `* Title: ${title}\n`;
2176
+ if (description) {
2177
+ const formattedDescription = description.replace(/\n/gm, "\n* ");
2178
+ banner += `* Description: ${formattedDescription}\n`;
2179
+ }
2180
+ if (version) banner += `* OpenAPI spec version: ${version}\n`;
2181
+ banner += "*/\n";
2182
+ return banner;
2183
+ } catch (_error) {
2184
+ return "/**\n* Generated by Kubb (https://kubb.dev/).\n* Do not edit manually.\n*/";
2185
+ }
2186
+ }
2187
+ /**
2188
+ * Default banner resolver — returns the banner string for a generated file.
2189
+ *
2190
+ * - When `output.banner` is a function and `node` is provided, calls it with the node.
2191
+ * - When `output.banner` is a function and `node` is absent, falls back to the default Kubb banner.
2192
+ * - When `output.banner` is a string, returns it directly.
2193
+ * - When `config.output.defaultBanner` is `false`, returns `undefined`.
2194
+ * - Otherwise returns the default "Generated by Kubb" banner.
2195
+ *
2196
+ * @example String banner
2197
+ * ```ts
2198
+ * defaultResolveBanner(undefined, { output: { banner: '// my banner' }, config })
2199
+ * // → '// my banner'
2200
+ * ```
2201
+ *
2202
+ * @example Function banner with node
2203
+ * ```ts
2204
+ * defaultResolveBanner(rootNode, { output: { banner: (node) => `// v${node.version}` }, config })
2205
+ * // → '// v3.0.0'
2206
+ * ```
2207
+ *
2208
+ * @example Disabled banner
2209
+ * ```ts
2210
+ * defaultResolveBanner(undefined, { config: { output: { defaultBanner: false }, ...config } })
2211
+ * // → undefined
2212
+ * ```
2213
+ */
2214
+ function defaultResolveBanner(node, { output, config }) {
2215
+ if (typeof output?.banner === "function") return node ? output.banner(node) : buildDefaultBanner({ config });
2216
+ if (typeof output?.banner === "string") return output.banner;
2217
+ if (config.output.defaultBanner === false) return;
2218
+ return buildDefaultBanner({ config });
2219
+ }
2220
+ /**
2221
+ * Default footer resolver — returns the footer string for a generated file.
2222
+ *
2223
+ * - When `output.footer` is a function and `node` is provided, calls it with the node.
2224
+ * - When `output.footer` is a function and `node` is absent, returns `undefined`.
2225
+ * - When `output.footer` is a string, returns it directly.
2226
+ * - Otherwise returns `undefined`.
2227
+ *
2228
+ * @example String footer
2229
+ * ```ts
2230
+ * defaultResolveFooter(undefined, { output: { footer: '// end of file' }, config })
2231
+ * // → '// end of file'
2232
+ * ```
2233
+ *
2234
+ * @example Function footer with node
2235
+ * ```ts
2236
+ * defaultResolveFooter(rootNode, { output: { footer: (node) => `// ${node.title}` }, config })
2237
+ * // → '// Pet Store'
2238
+ * ```
2239
+ */
2240
+ function defaultResolveFooter(node, { output }) {
2241
+ if (typeof output?.footer === "function") return node ? output.footer(node) : void 0;
2242
+ if (typeof output?.footer === "string") return output.footer;
2243
+ }
2244
+ /**
2245
+ * Defines a resolver for a plugin, injecting built-in defaults for name casing,
2246
+ * include/exclude/override filtering, path resolution, and file construction.
2247
+ *
2248
+ * All four defaults can be overridden by providing them in the builder function:
2249
+ * - `default` — name casing strategy (camelCase / PascalCase)
2250
+ * - `resolveOptions` — include/exclude/override filtering
2251
+ * - `resolvePath` — output path computation
2252
+ * - `resolveFile` — full `FabricFile.File` construction
2253
+ *
2254
+ * Methods in the builder have access to `this` (the full resolver object), so they
2255
+ * can call other resolver methods without circular imports.
2256
+ *
2257
+ * @example Basic resolver with naming helpers
2258
+ * ```ts
2005
2259
  * export const resolver = defineResolver<PluginTs>(() => ({
2006
2260
  * name: 'default',
2007
- * resolveName(name) {
2008
- * return this.default(name, 'function')
2261
+ * resolveName(node) {
2262
+ * return this.default(node.name, 'function')
2009
2263
  * },
2010
- * resolveTypedName(name) {
2011
- * return this.default(name, 'type')
2264
+ * resolveTypedName(node) {
2265
+ * return this.default(node.name, 'type')
2012
2266
  * },
2267
+ * }))
2268
+ * ```
2269
+ *
2270
+ * @example Override resolvePath for a custom output structure
2271
+ * ```ts
2272
+ * export const resolver = defineResolver<PluginTs>(() => ({
2273
+ * name: 'custom',
2274
+ * resolvePath({ baseName }, { root, output }) {
2275
+ * return path.resolve(root, output.path, 'generated', baseName)
2276
+ * },
2277
+ * }))
2278
+ * ```
2279
+ *
2280
+ * @example Use this.default inside a helper
2281
+ * ```ts
2282
+ * export const resolver = defineResolver<PluginTs>(() => ({
2283
+ * name: 'default',
2013
2284
  * resolveParamName(node, param) {
2014
- * return this.resolveName(`${node.operationId} ${param.in} ${param.name}`)
2285
+ * return this.default(`${node.operationId} ${param.in} ${param.name}`, 'type')
2015
2286
  * },
2016
2287
  * }))
2288
+ * ```
2017
2289
  */
2018
2290
  function defineResolver(build) {
2019
2291
  return {
2020
2292
  default: defaultResolver,
2021
2293
  resolveOptions: defaultResolveOptions,
2294
+ resolvePath: defaultResolvePath,
2295
+ resolveFile: defaultResolveFile,
2296
+ resolveBanner: defaultResolveBanner,
2297
+ resolveFooter: defaultResolveFooter,
2022
2298
  ...build()
2023
2299
  };
2024
2300
  }
@@ -2028,13 +2304,17 @@ function defineResolver(build) {
2028
2304
  * Renders a React component for a list of operation nodes (V2 generators).
2029
2305
  */
2030
2306
  async function renderOperations(nodes, options) {
2031
- const { config, fabric, plugin, Component, adapter } = options;
2307
+ const { config, fabric, plugin, Component, driver, adapter } = options;
2032
2308
  if (!Component) return;
2033
2309
  const fabricChild = createReactFabric();
2034
2310
  await fabricChild.render(/* @__PURE__ */ jsx(Fabric, {
2035
- meta: { plugin },
2311
+ meta: {
2312
+ plugin,
2313
+ driver
2314
+ },
2036
2315
  children: /* @__PURE__ */ jsx(Component, {
2037
2316
  config,
2317
+ plugin,
2038
2318
  adapter,
2039
2319
  nodes,
2040
2320
  options: options.options
@@ -2047,17 +2327,17 @@ async function renderOperations(nodes, options) {
2047
2327
  * Renders a React component for a single operation node (V2 generators).
2048
2328
  */
2049
2329
  async function renderOperation(node, options) {
2050
- const { config, fabric, plugin, Component, adapter, driver, mode } = options;
2330
+ const { config, fabric, plugin, Component, adapter, driver } = options;
2051
2331
  if (!Component) return;
2052
2332
  const fabricChild = createReactFabric();
2053
2333
  await fabricChild.render(/* @__PURE__ */ jsx(Fabric, {
2054
2334
  meta: {
2055
2335
  plugin,
2056
- driver,
2057
- mode
2336
+ driver
2058
2337
  },
2059
2338
  children: /* @__PURE__ */ jsx(Component, {
2060
2339
  config,
2340
+ plugin,
2061
2341
  adapter,
2062
2342
  node,
2063
2343
  options: options.options
@@ -2070,17 +2350,17 @@ async function renderOperation(node, options) {
2070
2350
  * Renders a React component for a single schema node (V2 generators).
2071
2351
  */
2072
2352
  async function renderSchema(node, options) {
2073
- const { config, fabric, plugin, Component, adapter, driver, mode } = options;
2353
+ const { config, fabric, plugin, Component, adapter, driver } = options;
2074
2354
  if (!Component) return;
2075
2355
  const fabricChild = createReactFabric();
2076
2356
  await fabricChild.render(/* @__PURE__ */ jsx(Fabric, {
2077
2357
  meta: {
2078
2358
  plugin,
2079
- driver,
2080
- mode
2359
+ driver
2081
2360
  },
2082
2361
  children: /* @__PURE__ */ jsx(Component, {
2083
2362
  config,
2363
+ plugin,
2084
2364
  adapter,
2085
2365
  node,
2086
2366
  options: options.options
@@ -2256,7 +2536,7 @@ async function detectFormatter() {
2256
2536
  //#region src/utils/TreeNode.ts
2257
2537
  /**
2258
2538
  * Tree structure used to build per-directory barrel (`index.ts`) files from a
2259
- * flat list of generated {@link KubbFile.File} entries.
2539
+ * flat list of generated {@link FabricFile.File} entries.
2260
2540
  *
2261
2541
  * Each node represents either a directory or a file within the output tree.
2262
2542
  * Use {@link TreeNode.build} to construct a root node from a file list, then
@@ -2298,24 +2578,39 @@ var TreeNode = class TreeNode {
2298
2578
  this.#cachedLeaves = leaves;
2299
2579
  return leaves;
2300
2580
  }
2581
+ /**
2582
+ * Visits this node and every descendant in depth-first order.
2583
+ */
2301
2584
  forEach(callback) {
2302
2585
  if (typeof callback !== "function") throw new TypeError("forEach() callback must be a function");
2303
2586
  callback(this);
2304
2587
  for (const child of this.children) child.forEach(callback);
2305
2588
  return this;
2306
2589
  }
2590
+ /**
2591
+ * Finds the first leaf that satisfies `predicate`, or `undefined` when none match.
2592
+ */
2307
2593
  findDeep(predicate) {
2308
2594
  if (typeof predicate !== "function") throw new TypeError("find() predicate must be a function");
2309
2595
  return this.leaves.find(predicate);
2310
2596
  }
2597
+ /**
2598
+ * Calls `callback` for every leaf of this node.
2599
+ */
2311
2600
  forEachDeep(callback) {
2312
2601
  if (typeof callback !== "function") throw new TypeError("forEach() callback must be a function");
2313
2602
  this.leaves.forEach(callback);
2314
2603
  }
2604
+ /**
2605
+ * Returns all leaves that satisfy `callback`.
2606
+ */
2315
2607
  filterDeep(callback) {
2316
2608
  if (typeof callback !== "function") throw new TypeError("filter() callback must be a function");
2317
2609
  return this.leaves.filter(callback);
2318
2610
  }
2611
+ /**
2612
+ * Maps every leaf through `callback` and returns the resulting array.
2613
+ */
2319
2614
  mapDeep(callback) {
2320
2615
  if (typeof callback !== "function") throw new TypeError("map() callback must be a function");
2321
2616
  return this.leaves.map(callback);
@@ -2401,7 +2696,7 @@ function buildDirectoryTree(files, rootFolder = "") {
2401
2696
  function getBarrelFilesByRoot(root, files) {
2402
2697
  const cachedFiles = /* @__PURE__ */ new Map();
2403
2698
  TreeNode.build(files, root)?.forEach((treeNode) => {
2404
- if (!treeNode || !treeNode.children || !treeNode.parent?.data.path) return;
2699
+ if (!treeNode?.children || !treeNode.parent?.data.path) return;
2405
2700
  const barrelFile = {
2406
2701
  path: join(treeNode.parent?.data.path, "index.ts"),
2407
2702
  baseName: "index.ts",
@@ -2488,7 +2783,15 @@ async function getConfigs(config, args) {
2488
2783
  //#endregion
2489
2784
  //#region src/utils/mergeResolvers.ts
2490
2785
  /**
2491
- * Merges an array of resolvers into a single resolver. Later entries override earlier ones (last wins).
2786
+ * Merges an ordered list of resolvers into a single resolver by shallow-merging each entry left to right.
2787
+ *
2788
+ * Later entries win when keys conflict, so the last resolver in the list takes highest precedence.
2789
+ *
2790
+ * @example
2791
+ * ```ts
2792
+ * const resolver = mergeResolvers(resolverTs, resolverTsLegacy)
2793
+ * // resolverTsLegacy methods override resolverTs where they overlap
2794
+ * ```
2492
2795
  */
2493
2796
  function mergeResolvers(...resolvers) {
2494
2797
  return resolvers.reduce((acc, curr) => ({
@@ -2499,21 +2802,25 @@ function mergeResolvers(...resolvers) {
2499
2802
  //#endregion
2500
2803
  //#region src/utils/getPreset.ts
2501
2804
  /**
2502
- * Resolves a named preset into merged resolvers and transformers.
2805
+ * Resolves a named preset into merged resolvers, transformers, and generators.
2503
2806
  *
2504
- * - Merges the preset's resolvers on top of the first (default) resolver to produce `baseResolver`.
2807
+ * - Merges the preset's resolvers on top of the first (default)
2505
2808
  * - Merges any additional user-supplied resolvers on top of that to produce the final `resolver`.
2506
2809
  * - Concatenates preset transformers before user-supplied transformers.
2810
+ * - Combines preset generators with user-supplied generators; falls back to the `default` preset's generators when neither provides any.
2507
2811
  */
2508
2812
  function getPreset(params) {
2509
- const { preset: presetName, presets, resolvers, transformers: userTransformers } = params;
2813
+ const { preset: presetName, presets, resolvers, transformers: userTransformers, generators: userGenerators } = params;
2510
2814
  const [defaultResolver, ...userResolvers] = resolvers;
2511
2815
  const preset = presets[presetName];
2512
- const baseResolver = mergeResolvers(defaultResolver, ...preset?.resolvers ?? []);
2816
+ const resolver = mergeResolvers(mergeResolvers(defaultResolver, ...preset?.resolvers ?? []), ...userResolvers ?? []);
2817
+ const transformers = [...preset?.transformers ?? [], ...userTransformers ?? []];
2818
+ const presetGenerators = preset?.generators ?? [];
2819
+ const defaultPresetGenerators = presets["default"]?.generators ?? [];
2513
2820
  return {
2514
- baseResolver,
2515
- resolver: mergeResolvers(baseResolver, ...userResolvers ?? []),
2516
- transformers: [...preset?.transformers ?? [], ...userTransformers ?? []],
2821
+ resolver,
2822
+ transformers,
2823
+ generators: presetGenerators.length > 0 || userGenerators.length ? [...presetGenerators, ...userGenerators] : defaultPresetGenerators,
2517
2824
  preset
2518
2825
  };
2519
2826
  }
@@ -2600,6 +2907,6 @@ function satisfiesDependency(dependency, version, cwd) {
2600
2907
  return satisfies(semVer, version);
2601
2908
  }
2602
2909
  //#endregion
2603
- export { AsyncEventEmitter, FunctionParams, PluginDriver, URLPath, build, build as default, createAdapter, createPlugin, createStorage, defaultResolveOptions, defineConfig, defineGenerator, defineLogger, definePreset, definePresets, definePrinter, defineResolver, detectFormatter, detectLinter, formatters, fsStorage, getBarrelFiles, getConfigs, getMode, getPreset, isInputPath, linters, logLevel, memoryStorage, mergeResolvers, renderOperation, renderOperations, renderSchema, safeBuild, satisfiesDependency, setup };
2910
+ export { AsyncEventEmitter, FunctionParams, PluginDriver, URLPath, build, build as default, buildDefaultBanner, createAdapter, createPlugin, createStorage, defaultResolveBanner, defaultResolveFile, defaultResolveFooter, defaultResolveOptions, defaultResolvePath, defineBuilder, defineConfig, defineGenerator, defineLogger, definePreset, definePresets, definePrinter, defineResolver, detectFormatter, detectLinter, formatters, fsStorage, getBarrelFiles, getConfigs, getMode, getPreset, isInputPath, linters, logLevel, memoryStorage, mergeResolvers, renderOperation, renderOperations, renderSchema, safeBuild, satisfiesDependency, setup };
2604
2911
 
2605
2912
  //# sourceMappingURL=index.js.map