@kubb/core 5.12.7 → 5.13.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.
@@ -3,7 +3,7 @@ import { satisfies } from "verkit";
3
3
  import { AsyncLocalStorage } from "node:async_hooks";
4
4
  import process$1 from "node:process";
5
5
  import { x } from "tinyexec";
6
- import { glob, mkdir, mkdtemp, readFile, rm, rm as rm$1, writeFile } from "node:fs/promises";
6
+ import { access, glob, mkdir, mkdtemp, readFile, rm, rm as rm$1, writeFile } from "node:fs/promises";
7
7
  import path, { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
8
8
  import { existsSync as existsSync$1 } from "node:fs";
9
9
  import { stripVTControlCharacters, styleText } from "node:util";
@@ -19,7 +19,7 @@ var __name = (target, value) => __defProp(target, "name", {
19
19
  });
20
20
  //#endregion
21
21
  //#region package.json
22
- var version = "5.12.7";
22
+ var version = "5.13.0";
23
23
  //#endregion
24
24
  //#region ../../internals/utils/src/casing.ts
25
25
  /**
@@ -102,20 +102,6 @@ function getErrorChain(error) {
102
102
  return chain;
103
103
  }
104
104
  //#endregion
105
- //#region ../../internals/utils/src/jsonPointer.ts
106
- /**
107
- * Escapes a single JSON pointer reference token per RFC 6901 (`~` → `~0`, `/` → `~1`), so a
108
- * name holding those characters maps to a distinct pointer.
109
- *
110
- * @example
111
- * ```ts
112
- * escapePointerToken('/pets/{id}') // '~1pets~1{id}'
113
- * ```
114
- */
115
- function escapePointerToken(token) {
116
- return token.replaceAll("~", "~0").replaceAll("/", "~1");
117
- }
118
- //#endregion
119
105
  //#region ../../internals/utils/src/runtime.ts
120
106
  const isBun = typeof Bun !== "undefined";
121
107
  const isDeno = "Deno" in globalThis;
@@ -148,6 +134,21 @@ function detect() {
148
134
  //#endregion
149
135
  //#region ../../internals/utils/src/fs.ts
150
136
  /**
137
+ * Resolves to `true` when the file or directory at `path` exists.
138
+ * Uses `Bun.file().exists()` when running under Bun, `fs.access` otherwise.
139
+ *
140
+ * @example
141
+ * ```ts
142
+ * if (await exists('./kubb.config.ts')) {
143
+ * const content = await read('./kubb.config.ts')
144
+ * }
145
+ * ```
146
+ */
147
+ async function exists(path) {
148
+ if (runtime.isBun) return Bun.file(path).exists();
149
+ return access(path).then(() => true, () => false);
150
+ }
151
+ /**
151
152
  * Reads the file at `path` as a UTF-8 string.
152
153
  * Uses `Bun.file().text()` when running under Bun, `fs.readFile` otherwise.
153
154
  *
@@ -1660,13 +1661,13 @@ var Resolver = class Resolver {
1660
1661
  const resolveName = name ?? ((schemaName) => this.name(schemaName));
1661
1662
  return collectImportedRefNames(node).map((schemaName) => ast.factory.createImport({
1662
1663
  name: [resolveName(schemaName)],
1663
- path: this.file({
1664
+ path: this.#resolveFilePath({
1664
1665
  name: schemaName,
1665
1666
  extname,
1666
1667
  root,
1667
1668
  output,
1668
1669
  group
1669
- }).path
1670
+ })
1670
1671
  }));
1671
1672
  }
1672
1673
  /**
@@ -1825,19 +1826,13 @@ var Resolver = class Resolver {
1825
1826
  });
1826
1827
  return resolved;
1827
1828
  }
1828
- /**
1829
- * Builds a `FileNode`. When `#filePath` (the resolver's `file.path`) is set it owns the whole
1830
- * path; otherwise the base name (from `#baseName`, the resolver's `file.baseName` or the
1831
- * built-in `toBaseName`) is placed by the `output.path`/`group` layout. The resolved file starts
1832
- * with empty `sources`, `imports`, and `exports`, which consumers populate separately.
1833
- */
1834
- #resolveFile(options) {
1835
- const { name, extname, tag, path: groupPath, root, output, group } = options;
1829
+ /** The absolute path `#resolveFile` places a file at. */
1830
+ #resolveFilePath({ name, extname, tag, path: groupPath, root, output, group }) {
1836
1831
  const baseName = this.#baseName({
1837
1832
  name,
1838
1833
  extname
1839
1834
  });
1840
- const filePath = this.#filePath ? this.#resolveOverridePath(this.#filePath({
1835
+ return this.#filePath ? this.#resolveOverridePath(this.#filePath({
1841
1836
  baseName,
1842
1837
  output
1843
1838
  }), root) : this.#resolvePath({
@@ -1848,6 +1843,15 @@ var Resolver = class Resolver {
1848
1843
  output,
1849
1844
  group
1850
1845
  });
1846
+ }
1847
+ /**
1848
+ * Builds a `FileNode`. When `#filePath` (the resolver's `file.path`) is set it owns the whole
1849
+ * path; otherwise the base name (from `#baseName`, the resolver's `file.baseName` or the
1850
+ * built-in `toBaseName`) is placed by the `output.path`/`group` layout. The resolved file starts
1851
+ * with empty `sources`, `imports`, and `exports`, which consumers populate separately.
1852
+ */
1853
+ #resolveFile(options) {
1854
+ const filePath = this.#resolveFilePath(options);
1851
1855
  return ast.factory.createFile({
1852
1856
  path: filePath,
1853
1857
  baseName: path.basename(filePath),
@@ -2119,6 +2123,17 @@ function createProgress(files, config, hooks) {
2119
2123
  if (updates.length) await hooks.callHook("kubb:files:processing:update", { files: updates });
2120
2124
  };
2121
2125
  }
2126
+ /** Links each source without a pointer to the node its file was generated from. */
2127
+ function withPointer(files, pointer) {
2128
+ if (!pointer) return files;
2129
+ return files.map((file) => ({
2130
+ ...file,
2131
+ sources: file.sources.map((source) => source.pointer ? source : {
2132
+ ...source,
2133
+ pointer
2134
+ })
2135
+ }));
2136
+ }
2122
2137
  /**
2123
2138
  * In-memory file store for generated files, and the writer that turns them into source
2124
2139
  * strings on `storage`. Files sharing a `path` are merged (sources/imports/exports
@@ -2137,6 +2152,7 @@ var FileManager = class {
2137
2152
  #cache = /* @__PURE__ */ new Map();
2138
2153
  #pending = /* @__PURE__ */ new Set();
2139
2154
  #sorted = null;
2155
+ #merges = /* @__PURE__ */ new WeakSet();
2140
2156
  add(...files) {
2141
2157
  return this.#store(files, false);
2142
2158
  }
@@ -2144,18 +2160,18 @@ var FileManager = class {
2144
2160
  return this.#store(files, true);
2145
2161
  }
2146
2162
  /** Stores a generator result: a file array is upserted as is, an element renders through `renderer` first, falsy is a no-op. */
2147
- async dispatch({ result, renderer }) {
2163
+ async dispatch({ result, renderer, pointer }) {
2148
2164
  try {
2149
2165
  var _usingCtx$1 = _usingCtx();
2150
2166
  if (!result) return;
2151
2167
  if (Array.isArray(result)) {
2152
- this.#defer(result);
2168
+ this.#defer(withPointer(result, pointer));
2153
2169
  return;
2154
2170
  }
2155
2171
  if (!renderer) return;
2156
2172
  const instance = _usingCtx$1.u(renderer());
2157
2173
  await instance.render(result);
2158
- this.#defer(instance.files);
2174
+ this.#defer(withPointer(instance.files, pointer));
2159
2175
  } catch (_) {
2160
2176
  _usingCtx$1.e = _;
2161
2177
  } finally {
@@ -2165,9 +2181,24 @@ var FileManager = class {
2165
2181
  /** Upserts without normalizing: the raw merge waits in `#pending` until the file is read. */
2166
2182
  #defer(files) {
2167
2183
  for (const file of files) {
2168
- const existing = this.#cache.get(file.path);
2169
- this.#cache.set(file.path, existing ? mergeFile(existing, file) : file);
2170
2184
  this.#pending.add(file.path);
2185
+ const existing = this.#cache.get(file.path);
2186
+ if (!existing) {
2187
+ this.#cache.set(file.path, file);
2188
+ continue;
2189
+ }
2190
+ if (!this.#merges.has(existing)) {
2191
+ const merged = mergeFile(existing, file);
2192
+ this.#merges.add(merged);
2193
+ this.#cache.set(file.path, merged);
2194
+ continue;
2195
+ }
2196
+ existing.banner = file.banner;
2197
+ existing.footer = file.footer;
2198
+ existing.copy = file.copy ?? existing.copy;
2199
+ existing.sources.push(...file.sources);
2200
+ existing.imports.push(...file.imports);
2201
+ existing.exports.push(...file.exports);
2171
2202
  }
2172
2203
  if (files.length > 0) this.#sorted = null;
2173
2204
  }
@@ -2346,24 +2377,23 @@ function assertPluginEntry(entry, index) {
2346
2377
  });
2347
2378
  }
2348
2379
  /**
2349
- * Where a generator crashed: a label naming the node and, when the node has one, a JSON pointer
2350
- * to it. Built from the node fields so core stays adapter-agnostic.
2380
+ * Where a generator crashed: a label naming the node and, when the adapter set one, the node's
2381
+ * pointer into the input.
2351
2382
  */
2352
2383
  function getCrashSite(node) {
2353
- if (node.kind === "Schema") return node.name ? {
2354
- label: `schema "${node.name}"`,
2355
- location: {
2384
+ if (node.kind === "Schema") return {
2385
+ label: node.name ? `schema "${node.name}"` : "an inline schema",
2386
+ location: node.pointer ? {
2356
2387
  kind: "schema",
2357
- pointer: `#/components/schemas/${escapePointerToken(node.name)}`
2358
- }
2359
- } : { label: "an inline schema" };
2360
- if (!node.method || !node.path) return { label: `operation "${node.operationId}"` };
2388
+ pointer: node.pointer
2389
+ } : void 0
2390
+ };
2361
2391
  return {
2362
- label: `operation "${node.operationId}" (${node.method.toUpperCase()} ${node.path})`,
2363
- location: {
2392
+ label: node.method && node.path ? `operation "${node.operationId}" (${node.method.toUpperCase()} ${node.path})` : `operation "${node.operationId}"`,
2393
+ location: node.pointer ? {
2364
2394
  kind: "operation",
2365
- pointer: `#/paths/${escapePointerToken(node.path)}/${node.method.toLowerCase()}`
2366
- }
2395
+ pointer: node.pointer
2396
+ } : void 0
2367
2397
  };
2368
2398
  }
2369
2399
  var KubbDriver = class {
@@ -2651,6 +2681,7 @@ var KubbDriver = class {
2651
2681
  hooks,
2652
2682
  config
2653
2683
  });
2684
+ await this.adapter?.settle?.();
2654
2685
  await hooks.callHook("kubb:build:end", {
2655
2686
  files: this.fileManager.files,
2656
2687
  config,
@@ -2658,6 +2689,7 @@ var KubbDriver = class {
2658
2689
  });
2659
2690
  return { diagnostics: Diagnostics.dedupe(diagnostics) };
2660
2691
  } catch (caughtError) {
2692
+ await this.adapter?.settle?.();
2661
2693
  diagnostics.push(Diagnostics.from(caughtError));
2662
2694
  return { diagnostics: Diagnostics.dedupe(diagnostics) };
2663
2695
  }
@@ -2886,7 +2918,8 @@ var KubbDriver = class {
2886
2918
  if (!(generator.match ? await generator.match(node, ctx) : true)) continue;
2887
2919
  await this.fileManager.dispatch({
2888
2920
  result: await generate(generator),
2889
- renderer: generator.renderer
2921
+ renderer: generator.renderer,
2922
+ pointer: node.pointer
2890
2923
  });
2891
2924
  }
2892
2925
  }
@@ -3115,6 +3148,6 @@ var Hookable = class {
3115
3148
  }
3116
3149
  };
3117
3150
  //#endregion
3118
- export { formatMs as A, toError as B, useConfig as C, defineExtension as D, checkCompatibility as E, listFiles as F, __name as H, read as I, rm$1 as L, inParallel as M, existsSync$1 as N, resolveMeta as O, isPathInside as P, write as R, tryUseKubb as S, useOptions as T, camelCase as V, kubbContext as _, FileManager as a, setOptions as b, Resolver as c, isPublicAddress as d, assertPluginOption as f, injectFile as g, addMacro as h, createNodeCache as i, getElapsedMs as j, Diagnostics as k, getInputKind as l, addGenerator as m, KubbDriver as n, _usingCtx as o, definePlugin as p, pluginNotFoundError as r, createResolver as s, Hookable as t, checkoutGitInput as u, requirePlugin as v, useKubb as w, setResolver as x, setMacros as y, writeRaw as z };
3151
+ export { formatMs as A, writeRaw as B, useConfig as C, defineExtension as D, checkCompatibility as E, isPathInside as F, camelCase as H, listFiles as I, read as L, inParallel as M, exists as N, resolveMeta as O, existsSync$1 as P, rm$1 as R, tryUseKubb as S, useOptions as T, __name as U, toError as V, kubbContext as _, FileManager as a, setOptions as b, Resolver as c, isPublicAddress as d, assertPluginOption as f, injectFile as g, addMacro as h, createNodeCache as i, getElapsedMs as j, Diagnostics as k, getInputKind as l, addGenerator as m, KubbDriver as n, _usingCtx as o, definePlugin as p, pluginNotFoundError as r, createResolver as s, Hookable as t, checkoutGitInput as u, requirePlugin as v, useKubb as w, setResolver as x, setMacros as y, write as z };
3119
3152
 
3120
- //# sourceMappingURL=Hookable-BRD9qP-V.js.map
3153
+ //# sourceMappingURL=Hookable-BR69O7aj.js.map