@kubb/adapter-oas 5.14.3 → 5.14.5

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.cjs CHANGED
@@ -23,6 +23,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
23
23
  //#endregion
24
24
  let _kubb_core = require("@kubb/core");
25
25
  let _kubb_kit = require("@kubb/kit");
26
+ let node_path = require("node:path");
26
27
  let node_fs_promises = require("node:fs/promises");
27
28
  let _scalar_openapi_upgrader = require("@scalar/openapi-upgrader");
28
29
  let api_ref_bundler = require("api-ref-bundler");
@@ -36,7 +37,7 @@ var compatibility = {
36
37
  };
37
38
  //#endregion
38
39
  //#region package.json
39
- var version = "5.14.3";
40
+ var version = "5.14.5";
40
41
  //#endregion
41
42
  //#region src/constants.ts
42
43
  /**
@@ -727,33 +728,55 @@ function inlinePathRefs(node, resolve, visiting = []) {
727
728
  * all-internal document it is a no-op that still walks the whole tree to confirm that, which
728
729
  * costs real time on a large spec.
729
730
  *
731
+ * `document` stands in for the file at `pathOrUrl`, such as inline input. Every other file or URL
732
+ * read, including one that fails, lands in `sources`. A `$ref` that cannot be read reports
733
+ * `KUBB_REF_NOT_FOUND` at the key that holds it.
734
+ *
730
735
  * @example Local file
731
736
  * `const document = await bundleDocument('./openapi.yaml')`
732
737
  *
733
738
  * @example Remote URL
734
739
  * `const document = await bundleDocument('https://example.com/openapi.yaml')`
735
740
  */
736
- async function bundleDocument(pathOrUrl) {
741
+ async function bundleDocument(pathOrUrl, { document, sources = [] } = {}) {
737
742
  const cache = /* @__PURE__ */ new Map();
743
+ const toKey = (sourcePath) => urlRegExp.test(sourcePath) ? new URL(sourcePath).href : sourcePath;
738
744
  const resolver = (sourcePath) => {
739
- const key = urlRegExp.test(sourcePath) ? new URL(sourcePath).href : sourcePath;
745
+ if (document && sourcePath === pathOrUrl) return Promise.resolve(document);
746
+ const key = toKey(sourcePath);
740
747
  const cached = cache.get(key);
741
748
  if (cached) return cached;
749
+ sources.push(key);
742
750
  const result = resolveSource(sourcePath);
743
751
  cache.set(key, result);
744
752
  return result;
745
753
  };
746
754
  const root = await resolver(pathOrUrl);
747
755
  if (typeof root === "object" && root !== null && !hasExternalRef(root)) return root;
748
- return await (0, api_ref_bundler.bundle)(pathOrUrl, resolver);
756
+ return await (0, api_ref_bundler.bundle)(pathOrUrl, resolver, { hooks: { onError: (message, { path, state }) => {
757
+ const pointer = toKey(state.baseFile) === toKey(pathOrUrl) ? `#/${path.map((token) => escapePointerToken(String(token))).join("/")}` : void 0;
758
+ const diagnostic = {
759
+ code: _kubb_kit.Diagnostics.code.refNotFound,
760
+ severity: "error",
761
+ message: `Could not bundle an external \`$ref\`. ${message}.`,
762
+ help: "Check that the file or URL the `$ref` points at exists and is readable, or fix the `$ref`.",
763
+ ...pointer && { location: {
764
+ kind: "schema",
765
+ pointer
766
+ } }
767
+ };
768
+ if (!_kubb_kit.Diagnostics.report(diagnostic)) throw new _kubb_kit.Diagnostics.Error(diagnostic);
769
+ } } });
749
770
  }
771
+ const inlineInputName = "<inline input>";
750
772
  /**
751
773
  * Creates a `Document` from an `AdapterSource`.
752
774
  *
753
775
  * - `{ type: 'path' }` bundles an absolute file path (core resolves `input`) or remote URL via
754
776
  * `api-ref-bundler`, hoisting external file schemas into named `components.schemas` entries so
755
777
  * generators can emit named types and imports.
756
- * - `{ type: 'data' }` parses an inline string (YAML/JSON) or raw object.
778
+ * - `{ type: 'data' }` parses an inline string (YAML/JSON) or raw object, then bundles its
779
+ * external `$ref`s from `root` when it has any. Each file or URL read lands in `sources`.
757
780
  *
758
781
  * Swagger 2.0 and OpenAPI 3.0 documents are up-converted to OpenAPI 3.1 via `@scalar/openapi-upgrader`.
759
782
  *
@@ -763,14 +786,20 @@ async function bundleDocument(pathOrUrl) {
763
786
  * const document = await parseFromConfig({ type: 'data', data: '{"openapi":"3.0.0",...}' })
764
787
  * ```
765
788
  */
766
- async function parseFromConfig(source) {
789
+ async function parseFromConfig(source, sources = []) {
767
790
  const raw = await (async () => {
768
- if (source.type === "data") return typeof source.data === "string" ? parseYaml(source.data, {
769
- origin: "the inline `input` string",
770
- help: "Fix the syntax at the reported line. Kubb reads `input` as an inline spec, not a file path, because it starts with `{`, `[`, `openapi:`, or `swagger:`, or spans several lines."
771
- }) : structuredClone(source.data);
791
+ if (source.type === "data") {
792
+ const data = typeof source.data === "string" ? parseYaml(source.data, {
793
+ origin: "the inline `input` string",
794
+ help: "Fix the syntax at the reported line. Kubb reads `input` as an inline spec, not a file path, because it starts with `{`, `[`, `openapi:`, or `swagger:`, or spans several lines."
795
+ }) : structuredClone(source.data);
796
+ return source.root && hasExternalRef(data) ? bundleDocument((0, node_path.join)(source.root, inlineInputName), {
797
+ document: data,
798
+ sources
799
+ }) : data;
800
+ }
772
801
  await assertInputExists(source.path);
773
- return bundleDocument(source.path);
802
+ return bundleDocument(source.path, { sources });
774
803
  })();
775
804
  if (raw && typeof raw === "object") {
776
805
  const document = raw;
@@ -2905,6 +2934,7 @@ const adapterOas = (0, _kubb_core.defineExtension)({
2905
2934
  }),
2906
2935
  build({ validate, contentType, server, discriminator, enums, ...parserOptions }) {
2907
2936
  let parsedDocument = null;
2937
+ let sources = [];
2908
2938
  const pendingValidations = [];
2909
2939
  const inputCache = /* @__PURE__ */ new WeakMap();
2910
2940
  /**
@@ -3038,6 +3068,9 @@ const adapterOas = (0, _kubb_core.defineExtension)({
3038
3068
  get document() {
3039
3069
  return parsedDocument;
3040
3070
  },
3071
+ get sources() {
3072
+ return sources;
3073
+ },
3041
3074
  locate,
3042
3075
  async validate(input, options) {
3043
3076
  const document = await parseFromConfig({
@@ -3053,9 +3086,14 @@ const adapterOas = (0, _kubb_core.defineExtension)({
3053
3086
  async parse(source, { signal } = {}) {
3054
3087
  signal?.throwIfAborted();
3055
3088
  const cached = inputCache.get(source);
3056
- if (cached) return cached;
3089
+ if (cached) {
3090
+ sources = cached.sources;
3091
+ return cached.promise;
3092
+ }
3093
+ const read = [];
3094
+ sources = read;
3057
3095
  const promise = (async () => {
3058
- const document = await parseFromConfig(source);
3096
+ const document = await parseFromConfig(source, read);
3059
3097
  signal?.throwIfAborted();
3060
3098
  assertDocument(document);
3061
3099
  if (validate) pendingValidations.push(validateDocumentInWorker(document));
@@ -3075,7 +3113,10 @@ const adapterOas = (0, _kubb_core.defineExtension)({
3075
3113
  })
3076
3114
  });
3077
3115
  })();
3078
- inputCache.set(source, promise);
3116
+ inputCache.set(source, {
3117
+ promise,
3118
+ sources: read
3119
+ });
3079
3120
  return promise.catch((error) => {
3080
3121
  if (signal?.aborted) inputCache.delete(source);
3081
3122
  throw error;