schema-components 1.23.0 → 1.24.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.
@@ -1,5 +1,5 @@
1
1
  import { m as JsonObject, w as SchemaMeta } from "../types-BTB73MB8.mjs";
2
- import { i as DiagnosticsOptions } from "../diagnostics-BS2kaUyE.mjs";
2
+ import { i as DiagnosticsOptions } from "../diagnostics-Cbwak-ZX.mjs";
3
3
 
4
4
  //#region src/core/adapter.d.ts
5
5
  type SchemaInput = Record<string, unknown>;
@@ -65,7 +65,7 @@ declare function detectSchemaKind(input: unknown): SchemaKind;
65
65
  * "Cannot read properties of undefined".
66
66
  * - Transforms → zod-transform-unsupported. This also catches `z.codec(…)`
67
67
  * because Zod implements codecs as a pipe + transform internally, so
68
- * they trip the same processor when round-tripping is forced. (Plain
68
+ * they trip the same processor when round-tripping is forced. (Plain
69
69
  * `z.toJSONSchema(codec)` itself does NOT throw because Zod picks one
70
70
  * side of the codec; the static rejection in `typeInference.ts` is the
71
71
  * compile-time guard.)
@@ -1,5 +1,5 @@
1
1
  import { E as StringConstraints, f as FileConstraints, t as ArrayConstraints, x as ObjectConstraints, y as NumberConstraints } from "../types-BTB73MB8.mjs";
2
- import { i as DiagnosticsOptions } from "../diagnostics-BS2kaUyE.mjs";
2
+ import { i as DiagnosticsOptions } from "../diagnostics-Cbwak-ZX.mjs";
3
3
 
4
4
  //#region src/core/constraints.d.ts
5
5
  declare function extractStringConstraints(schema: Record<string, unknown>, diagnostics?: DiagnosticsOptions, pointer?: string): StringConstraints;
@@ -1,2 +1,2 @@
1
- import { a as appendPointer, i as DiagnosticsOptions, n as DiagnosticCode, o as emitDiagnostic, r as DiagnosticSink, t as Diagnostic } from "../diagnostics-BS2kaUyE.mjs";
1
+ import { a as appendPointer, i as DiagnosticsOptions, n as DiagnosticCode, o as emitDiagnostic, r as DiagnosticSink, t as Diagnostic } from "../diagnostics-Cbwak-ZX.mjs";
2
2
  export { Diagnostic, DiagnosticCode, DiagnosticSink, DiagnosticsOptions, appendPointer, emitDiagnostic };
@@ -1,4 +1,4 @@
1
- import { i as DiagnosticsOptions } from "../diagnostics-BS2kaUyE.mjs";
1
+ import { i as DiagnosticsOptions } from "../diagnostics-Cbwak-ZX.mjs";
2
2
 
3
3
  //#region src/core/formats.d.ts
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { i as DiagnosticsOptions } from "../diagnostics-BS2kaUyE.mjs";
1
+ import { i as DiagnosticsOptions } from "../diagnostics-Cbwak-ZX.mjs";
2
2
 
3
3
  //#region src/core/merge.d.ts
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { i as DiagnosticsOptions } from "../diagnostics-BS2kaUyE.mjs";
1
+ import { i as DiagnosticsOptions } from "../diagnostics-Cbwak-ZX.mjs";
2
2
  import { i as OpenApiVersionInfo, r as JsonSchemaDraft } from "../version-BFTVLsdb.mjs";
3
3
 
4
4
  //#region src/core/normalise.d.ts
@@ -1,2 +1,2 @@
1
- import { a as dereference, i as countDistinctRefs, n as RECURSIVE_ANCHOR_SENTINEL, o as findAnchor, r as RefOptions, s as resolveRef, t as ExternalResolver } from "../ref-DjLEKa_E.mjs";
1
+ import { a as dereference, i as countDistinctRefs, n as RECURSIVE_ANCHOR_SENTINEL, o as findAnchor, r as RefOptions, s as resolveRef, t as ExternalResolver } from "../ref-DCDuswPe.mjs";
2
2
  export { ExternalResolver, RECURSIVE_ANCHOR_SENTINEL, RefOptions, countDistinctRefs, dereference, findAnchor, resolveRef };
package/dist/core/ref.mjs CHANGED
@@ -24,11 +24,10 @@ const RECURSIVE_ANCHOR_SENTINEL = "__recursive__";
24
24
  * `false` → `{ not: {} }` (never-valid schema)
25
25
  *
26
26
  * Used by {@link resolveRef} so callers that expect an object schema
27
- * can continue without per-call-site boolean handling.
28
- *
29
- * TODO(round7-integration): once Agent D widens the walker's resolved-
30
- * ref handling to dispatch through `walkSubSchema`, drop this
31
- * translation and surface the boolean directly.
27
+ * can continue without per-call-site boolean handling. The walker's
28
+ * sub-schema dispatch (`walkSubSchema`) handles booleans natively at
29
+ * non-root positions; this translation covers the degenerate case
30
+ * where a top-level `$ref` resolves to a boolean schema.
32
31
  */
33
32
  function booleanSchemaToObject(value) {
34
33
  if (value) return {};
@@ -1,4 +1,4 @@
1
- import { i as DiagnosticsOptions } from "../diagnostics-BS2kaUyE.mjs";
1
+ import { i as DiagnosticsOptions } from "../diagnostics-Cbwak-ZX.mjs";
2
2
  import { NodeTransform } from "./normalise.mjs";
3
3
 
4
4
  //#region src/core/swagger2.d.ts
@@ -1,6 +1,6 @@
1
1
  import { A as UnknownField, D as StringField, b as NumberField, c as FieldBase, j as WalkedField, o as Editability, p as FileField, r as BooleanField, v as NullField, w as SchemaMeta } from "../types-BTB73MB8.mjs";
2
- import { i as DiagnosticsOptions } from "../diagnostics-BS2kaUyE.mjs";
3
- import { t as ExternalResolver } from "../ref-DjLEKa_E.mjs";
2
+ import { i as DiagnosticsOptions } from "../diagnostics-Cbwak-ZX.mjs";
3
+ import { t as ExternalResolver } from "../ref-DCDuswPe.mjs";
4
4
 
5
5
  //#region src/core/walkBuilders.d.ts
6
6
  declare function getString(obj: Record<string, unknown>, key: string): string | undefined;
@@ -16,7 +16,7 @@
16
16
  * Machine-readable codes identifying each class of diagnostic.
17
17
  * Stable across releases — consumers can pattern-match on these.
18
18
  */
19
- type DiagnosticCode = "allof-conflict" | "assumed-draft" | "bare-exclusive-bound" | "conditional-fallback" | "cross-schema-relative-ref-unsupported" | "cyclic-path-item-ref" | "dependencies-conflict" | "dependent-required-invalid" | "depth-exceeded" | "discriminator-inconsistent" | "divisible-by-conflict" | "doc-not-object" | "dropped-swagger-feature" | "duplicate-body-parameter" | "duplicate-operation-id" | "dynamic-ref-degraded" | "enum-value-filtered" | "external-ref" | "invalid-const" | "invalid-id-fragment" | "keyword-out-of-draft" | "legacy-dependencies-split" | "legacy-dependencies-split-2019" | "non-json-media-type-fallback" | "parameter-missing-schema" | "path-item-ref-too-deep" | "path-webhook-name-collision" | "pattern-invalid" | "prototype-polluting-property" | "recursive-anchor-collision" | "relative-ref-resolved" | "required-non-string" | "schema-allof-incompatible" | "swagger-collection-format-dropped" | "swagger-cyclic-parameter-ref" | "swagger-invalid-file-parameter" | "swagger-malformed-oauth-flow" | "swagger-missing-consumes" | "swagger-missing-host" | "type-mismatch" | "type-negation-fallback" | "unknown-format" | "unknown-json-schema-dialect" | "unknown-keyword" | "unknown-openapi-version" | "unknown-parameter-location" | "unknown-security-scheme-type" | "unresolved-ref" | "unsupported-type" | "zod-codec-nested-output-only" | "zod-codec-output-only" | "zod-preprocess-output-only" | "zod-promise-nested-unwrap";
19
+ type DiagnosticCode = "allof-conflict" | "assumed-draft" | "bare-exclusive-bound" | "conditional-fallback" | "cross-schema-relative-ref-unsupported" | "cyclic-header-ref" | "cyclic-link-ref" | "cyclic-parameter-ref" | "cyclic-path-item-ref" | "dependencies-conflict" | "dependent-required-invalid" | "depth-exceeded" | "discriminator-inconsistent" | "divisible-by-conflict" | "doc-not-object" | "dropped-swagger-feature" | "header-ref-too-deep" | "duplicate-body-parameter" | "duplicate-operation-id" | "dynamic-ref-degraded" | "enum-value-filtered" | "external-ref" | "invalid-const" | "invalid-id-fragment" | "keyword-out-of-draft" | "link-ref-too-deep" | "legacy-dependencies-split" | "legacy-dependencies-split-2019" | "non-json-media-type-fallback" | "parameter-missing-schema" | "parameter-ref-too-deep" | "path-item-ref-too-deep" | "path-webhook-name-collision" | "pattern-invalid" | "prototype-polluting-property" | "recursive-anchor-collision" | "relative-ref-resolved" | "required-non-string" | "schema-allof-incompatible" | "swagger-collection-format-dropped" | "swagger-cyclic-parameter-ref" | "swagger-invalid-file-parameter" | "swagger-malformed-oauth-flow" | "swagger-missing-consumes" | "swagger-missing-host" | "type-mismatch" | "type-negation-fallback" | "unknown-format" | "unknown-json-schema-dialect" | "unknown-keyword" | "unknown-openapi-version" | "unknown-parameter-location" | "unknown-security-scheme-type" | "unresolved-ref" | "unsupported-type" | "zod-codec-nested-output-only" | "zod-codec-output-only" | "zod-preprocess-output-only" | "zod-promise-nested-unwrap";
20
20
  /**
21
21
  * A single diagnostic emitted during schema processing.
22
22
  */
@@ -9,16 +9,11 @@ import { matchUnionOption } from "../core/unionMatch.mjs";
9
9
  * `aria-controls`, `aria-labelledby`, and `htmlFor` references resolve
10
10
  * consistently across the React, sync-HTML, and streaming-HTML outputs.
11
11
  *
12
- * The wrapper tolerates an empty path here (returning `sc-`) for the
13
- * sole reason that a leaf renderer at the schema root would otherwise
14
- * throw `renderToHtml(z.string())` is a rare but valid call shape.
15
- * Container renderers thread a non-empty path through `renderChild`, so
16
- * the empty-id fallback can never produce sibling collisions inside a
17
- * structured form.
18
- *
19
- * TODO(round7-integration): once `renderToHtml` always threads a stable
20
- * root path (e.g. `"$"`) into the leaf renderers, drop this wrapper and
21
- * call `fieldDomId` directly so the throw fires as designed.
12
+ * The wrapper tolerates an empty path here (returning `sc-`) so that
13
+ * a leaf renderer at the schema root `renderToHtml(z.string())` — has
14
+ * a usable id without throwing. Container renderers always thread a
15
+ * non-empty path through `renderChild`, so the empty-id fallback can
16
+ * never produce sibling collisions inside a structured form.
22
17
  */
23
18
  declare function fieldId(path: string): string;
24
19
  /**
@@ -32,17 +27,11 @@ declare function fieldId(path: string): string;
32
27
  * Exported because `streamRenderers.ts` needs to derive identical ids
33
28
  * — the panel id on the `<div role="tabpanel">` must match the
34
29
  * `aria-controls` on every tab regardless of which pipeline rendered it.
35
- *
36
- * TODO(round7-integration): drop the empty-path branch once `renderToHtml`
37
- * threads a stable root path so `panelIdFor` can be called directly.
38
30
  */
39
31
  declare function panelId(path: string): string;
40
32
  /**
41
33
  * Tab id for tab `i` within a discriminated union at `path`. Mirror of
42
34
  * `panelId` above — see its comment.
43
- *
44
- * TODO(round7-integration): drop the empty-path branch once `renderToHtml`
45
- * threads a stable root path so `tabIdFor` can be called directly.
46
35
  */
47
36
  declare function tabId(path: string, i: number): string;
48
37
  declare const defaultHtmlResolver: HtmlResolver;
@@ -15,16 +15,11 @@ import { ariaDescribedByAttrs, ariaLabelAttrs, ariaReadonlyAttrs, ariaRequiredAt
15
15
  * `aria-controls`, `aria-labelledby`, and `htmlFor` references resolve
16
16
  * consistently across the React, sync-HTML, and streaming-HTML outputs.
17
17
  *
18
- * The wrapper tolerates an empty path here (returning `sc-`) for the
19
- * sole reason that a leaf renderer at the schema root would otherwise
20
- * throw `renderToHtml(z.string())` is a rare but valid call shape.
21
- * Container renderers thread a non-empty path through `renderChild`, so
22
- * the empty-id fallback can never produce sibling collisions inside a
23
- * structured form.
24
- *
25
- * TODO(round7-integration): once `renderToHtml` always threads a stable
26
- * root path (e.g. `"$"`) into the leaf renderers, drop this wrapper and
27
- * call `fieldDomId` directly so the throw fires as designed.
18
+ * The wrapper tolerates an empty path here (returning `sc-`) so that
19
+ * a leaf renderer at the schema root `renderToHtml(z.string())` — has
20
+ * a usable id without throwing. Container renderers always thread a
21
+ * non-empty path through `renderChild`, so the empty-id fallback can
22
+ * never produce sibling collisions inside a structured form.
28
23
  */
29
24
  function fieldId(path) {
30
25
  if (path.length === 0) return "sc-";
@@ -41,9 +36,6 @@ function fieldId(path) {
41
36
  * Exported because `streamRenderers.ts` needs to derive identical ids
42
37
  * — the panel id on the `<div role="tabpanel">` must match the
43
38
  * `aria-controls` on every tab regardless of which pipeline rendered it.
44
- *
45
- * TODO(round7-integration): drop the empty-path branch once `renderToHtml`
46
- * threads a stable root path so `panelIdFor` can be called directly.
47
39
  */
48
40
  function panelId(path) {
49
41
  if (path.length === 0) return `${fieldId(path)}-panel`;
@@ -52,9 +44,6 @@ function panelId(path) {
52
44
  /**
53
45
  * Tab id for tab `i` within a discriminated union at `path`. Mirror of
54
46
  * `panelId` above — see its comment.
55
- *
56
- * TODO(round7-integration): drop the empty-path branch once `renderToHtml`
57
- * threads a stable root path so `tabIdFor` can be called directly.
58
47
  */
59
48
  function tabId(path, i) {
60
49
  if (path.length === 0) return `${fieldId(path)}-tab-${String(i)}`;
@@ -1,5 +1,5 @@
1
1
  import { j as WalkedField } from "../types-BTB73MB8.mjs";
2
- import { i as DiagnosticsOptions } from "../diagnostics-BS2kaUyE.mjs";
2
+ import { i as DiagnosticsOptions } from "../diagnostics-Cbwak-ZX.mjs";
3
3
  import { o as HtmlResolver } from "../renderer-CXJ8y0qw.mjs";
4
4
  import { HtmlElement } from "./html.mjs";
5
5
 
@@ -1,5 +1,5 @@
1
1
  import { u as FieldOverride, w as SchemaMeta } from "../types-BTB73MB8.mjs";
2
- import { r as DiagnosticSink } from "../diagnostics-BS2kaUyE.mjs";
2
+ import { r as DiagnosticSink } from "../diagnostics-Cbwak-ZX.mjs";
3
3
  import { InferParameterOverrides, InferRequestBodyFields, InferResponseFields } from "../core/typeInference.mjs";
4
4
  import { WidgetMap } from "../react/SchemaComponent.mjs";
5
5
  import { ReactNode } from "react";
@@ -1,5 +1,5 @@
1
1
  import { m as JsonObject } from "../types-BTB73MB8.mjs";
2
- import { i as DiagnosticsOptions } from "../diagnostics-BS2kaUyE.mjs";
2
+ import { i as DiagnosticsOptions } from "../diagnostics-Cbwak-ZX.mjs";
3
3
 
4
4
  //#region src/openapi/parser.d.ts
5
5
  interface OpenApiDocument {
@@ -87,17 +87,26 @@ interface LinkInfo {
87
87
  }
88
88
  declare function parseOpenApiDocument(doc: JsonObject): OpenApiDocument;
89
89
  declare function getSchema(parsed: OpenApiDocument, ref: string): JsonObject | undefined;
90
- declare function listOperations(parsed: OpenApiDocument, diagnostics?: DiagnosticsOptions): OperationInfo[];
90
+ declare function listOperations(parsed: OpenApiDocument, diagnostics?: DiagnosticsOptions, seenIds?: Map<string, string>): OperationInfo[];
91
91
  declare function getParameters(parsed: OpenApiDocument, path: string, method: string, diagnostics?: DiagnosticsOptions): ParameterInfo[];
92
92
  declare function getRequestBody(parsed: OpenApiDocument, path: string, method: string): RequestBodyInfo | undefined;
93
93
  declare function getResponses(parsed: OpenApiDocument, path: string, method: string, diagnostics?: DiagnosticsOptions): ResponseInfo[];
94
94
  declare function getSecurityRequirements(parsed: OpenApiDocument, path: string, method: string): SecurityRequirement[];
95
95
  declare function getSecuritySchemes(parsed: OpenApiDocument): Map<string, SecurityScheme>;
96
96
  declare function getResponseHeaders(response: JsonObject, doc?: JsonObject, diagnostics?: DiagnosticsOptions): Map<string, HeaderInfo>;
97
- declare function listWebhooks(parsed: OpenApiDocument, diagnostics?: DiagnosticsOptions): WebhookInfo[];
97
+ declare function listWebhooks(parsed: OpenApiDocument, diagnostics?: DiagnosticsOptions, seenIds?: Map<string, string>): WebhookInfo[];
98
+ /**
99
+ * Enumerate every operation in the document — both the `paths` map and
100
+ * the OpenAPI 3.1 `webhooks` map — sharing a single `seenIds` cache so
101
+ * cross-list `operationId` collisions surface the same way as same-list
102
+ * collisions. Returns the path-operation list followed by webhook
103
+ * operations (flattened); callers that need the structured webhook
104
+ * grouping should call `listWebhooks` directly.
105
+ */
106
+ declare function listAllOperations(parsed: OpenApiDocument, diagnostics?: DiagnosticsOptions): OperationInfo[];
98
107
  declare function getExternalDocs(obj: JsonObject): ExternalDocs | undefined;
99
108
  declare function getXmlInfo(schema: JsonObject): XmlInfo | undefined;
100
109
  declare function listCallbacks(parsed: OpenApiDocument, path: string, method: string, diagnostics?: DiagnosticsOptions): CallbackInfo[];
101
110
  declare function getLinks(parsed: OpenApiDocument, path: string, method: string, statusCode: string, diagnostics?: DiagnosticsOptions): LinkInfo[];
102
111
  //#endregion
103
- export { CallbackInfo, ExternalDocs, HeaderInfo, LinkInfo, OpenApiDocument, OperationInfo, ParameterInfo, ParameterLocation, RequestBodyInfo, ResponseInfo, SecurityRequirement, SecurityScheme, WebhookInfo, XmlInfo, getExternalDocs, getLinks, getParameters, getRequestBody, getResponseHeaders, getResponses, getSchema, getSecurityRequirements, getSecuritySchemes, getXmlInfo, listCallbacks, listOperations, listWebhooks, parseOpenApiDocument };
112
+ export { CallbackInfo, ExternalDocs, HeaderInfo, LinkInfo, OpenApiDocument, OperationInfo, ParameterInfo, ParameterLocation, RequestBodyInfo, ResponseInfo, SecurityRequirement, SecurityScheme, WebhookInfo, XmlInfo, getExternalDocs, getLinks, getParameters, getRequestBody, getResponseHeaders, getResponses, getSchema, getSecurityRequirements, getSecuritySchemes, getXmlInfo, listAllOperations, listCallbacks, listOperations, listWebhooks, parseOpenApiDocument };
@@ -96,11 +96,39 @@ function lookupPathItem(parsed, path) {
96
96
  if (resolved !== void 0) return resolved;
97
97
  return resolvePathItem(parsed, getProperty(getProperty(parsed.doc, "webhooks"), path));
98
98
  }
99
- function listOperations(parsed, diagnostics) {
99
+ /**
100
+ * Record an `operationId` against a shared `seenIds` map and emit a
101
+ * `duplicate-operation-id` diagnostic when a subsequent location reuses
102
+ * the same identifier. Returns the original `operationId` so the caller
103
+ * can pass the value straight onto its `OperationInfo`.
104
+ *
105
+ * When the same map is threaded through `listOperations` and
106
+ * `listWebhooks` (see `listAllOperations`), cross-list collisions
107
+ * between a path operation and a webhook operation surface as the same
108
+ * diagnostic class as same-list collisions.
109
+ */
110
+ function recordOperationId(operationId, location, pointer, seenIds, diagnostics) {
111
+ if (operationId === void 0) return;
112
+ const firstSeenAt = seenIds.get(operationId);
113
+ if (firstSeenAt !== void 0) {
114
+ emitDiagnostic(diagnostics, {
115
+ code: "duplicate-operation-id",
116
+ message: `operationId "${operationId}" is declared more than once (first at ${firstSeenAt}, again at ${location})`,
117
+ pointer,
118
+ detail: {
119
+ operationId,
120
+ firstSeenAt,
121
+ duplicateAt: location
122
+ }
123
+ });
124
+ return;
125
+ }
126
+ seenIds.set(operationId, location);
127
+ }
128
+ function listOperations(parsed, diagnostics, seenIds = /* @__PURE__ */ new Map()) {
100
129
  const operations = [];
101
130
  const paths = getProperty(parsed.doc, "paths");
102
131
  if (!isObject(paths)) return operations;
103
- const seenIds = /* @__PURE__ */ new Map();
104
132
  for (const [path, rawPathItem] of Object.entries(paths)) {
105
133
  const pathItem = resolvePathItem(parsed, rawPathItem, diagnostics);
106
134
  if (pathItem === void 0) continue;
@@ -108,20 +136,7 @@ function listOperations(parsed, diagnostics) {
108
136
  const operation = getProperty(pathItem, method);
109
137
  if (!isObject(operation)) continue;
110
138
  const operationId = getString(operation, "operationId");
111
- if (operationId !== void 0) {
112
- const firstSeenAt = seenIds.get(operationId);
113
- if (firstSeenAt !== void 0) emitDiagnostic(diagnostics, {
114
- code: "duplicate-operation-id",
115
- message: `operationId "${operationId}" is declared more than once (first at ${firstSeenAt}, again at ${method.toUpperCase()} ${path})`,
116
- pointer: `/paths/${jsonPointerEscape(path)}/${method}/operationId`,
117
- detail: {
118
- operationId,
119
- firstSeenAt,
120
- duplicateAt: `${method.toUpperCase()} ${path}`
121
- }
122
- });
123
- else seenIds.set(operationId, `${method.toUpperCase()} ${path}`);
124
- }
139
+ recordOperationId(operationId, `${method.toUpperCase()} ${path}`, `/paths/${jsonPointerEscape(path)}/${method}/operationId`, seenIds, diagnostics);
125
140
  operations.push({
126
141
  path,
127
142
  method,
@@ -179,26 +194,21 @@ function extractParameterList(doc, parameters, pointerBase, diagnostics) {
179
194
  * length — a Reference Object whose target is itself a Reference Object
180
195
  * is legal. `resolveRefChain` centralises cycle and depth-cap protection.
181
196
  *
182
- * Cycles and over-deep chains reuse the existing `cyclic-path-item-ref`
183
- * and `path-item-ref-too-deep` diagnostic codes with a
184
- * `detail.kind: "<node-kind>"` discriminator (e.g. `"parameter"`,
185
- * `"header"`, `"link"`). There is no dedicated code per node kind in the
186
- * current `DiagnosticCode` union; consumers filter by `detail.kind` when
187
- * they care to distinguish the source.
188
- *
189
- * TODO(round7-integration): consider adding dedicated `cyclic-*-ref` /
190
- * `*-ref-too-deep` codes per node kind to `core/diagnostics.ts` so the
191
- * kind discriminator on `detail` is not needed. The existing Swagger
192
- * 2.0 path already uses a dedicated `swagger-cyclic-parameter-ref` for
193
- * the equivalent failure mode.
197
+ * Cycles and over-deep chains emit a dedicated diagnostic code per node
198
+ * kind (`cyclic-parameter-ref`, `parameter-ref-too-deep`, and the
199
+ * `header` / `link` equivalents), mirroring the existing
200
+ * `swagger-cyclic-parameter-ref` precedent so consumers can pattern-match
201
+ * directly on the code instead of filtering by `detail.kind`.
194
202
  */
195
203
  function resolveReferenceObjectChain(doc, node, kind, diagnostics) {
196
204
  const kindLabel = kind === "parameter" ? "Parameter Object" : kind === "header" ? "Header Object" : "Link Object";
205
+ const cyclicCode = kind === "parameter" ? "cyclic-parameter-ref" : kind === "header" ? "cyclic-header-ref" : "cyclic-link-ref";
206
+ const tooDeepCode = kind === "parameter" ? "parameter-ref-too-deep" : kind === "header" ? "header-ref-too-deep" : "link-ref-too-deep";
197
207
  return resolveRefChain(node, {
198
208
  lookup: (ref) => ref.startsWith("#/") ? resolveRefInDoc(doc, ref) : void 0,
199
209
  onCycle: (ref) => {
200
210
  emitDiagnostic(diagnostics, {
201
- code: "cyclic-path-item-ref",
211
+ code: cyclicCode,
202
212
  message: `Cyclic ${kindLabel} $ref "${ref}"`,
203
213
  pointer: ref,
204
214
  detail: {
@@ -209,7 +219,7 @@ function resolveReferenceObjectChain(doc, node, kind, diagnostics) {
209
219
  },
210
220
  onDepthExceeded: (ref) => {
211
221
  emitDiagnostic(diagnostics, {
212
- code: "path-item-ref-too-deep",
222
+ code: tooDeepCode,
213
223
  message: `${kindLabel} $ref chain exceeded the hop cap starting from "${ref}"`,
214
224
  pointer: ref,
215
225
  detail: {
@@ -451,7 +461,7 @@ function getResponseHeaders(response, doc, diagnostics) {
451
461
  }
452
462
  return result;
453
463
  }
454
- function listWebhooks(parsed, diagnostics) {
464
+ function listWebhooks(parsed, diagnostics, seenIds = /* @__PURE__ */ new Map()) {
455
465
  const result = [];
456
466
  const webhooks = getProperty(parsed.doc, "webhooks");
457
467
  if (!isObject(webhooks)) return result;
@@ -462,10 +472,12 @@ function listWebhooks(parsed, diagnostics) {
462
472
  for (const method of HTTP_METHODS) {
463
473
  const operation = getProperty(hookItem, method);
464
474
  if (!isObject(operation)) continue;
475
+ const operationId = getString(operation, "operationId");
476
+ recordOperationId(operationId, `${method.toUpperCase()} webhook:${name}`, `/webhooks/${jsonPointerEscape(name)}/${method}/operationId`, seenIds, diagnostics);
465
477
  operations.push({
466
478
  path: name,
467
479
  method,
468
- operationId: getString(operation, "operationId"),
480
+ operationId,
469
481
  summary: getString(operation, "summary"),
470
482
  description: getString(operation, "description"),
471
483
  deprecated: getProperty(operation, "deprecated") === true,
@@ -479,6 +491,20 @@ function listWebhooks(parsed, diagnostics) {
479
491
  }
480
492
  return result;
481
493
  }
494
+ /**
495
+ * Enumerate every operation in the document — both the `paths` map and
496
+ * the OpenAPI 3.1 `webhooks` map — sharing a single `seenIds` cache so
497
+ * cross-list `operationId` collisions surface the same way as same-list
498
+ * collisions. Returns the path-operation list followed by webhook
499
+ * operations (flattened); callers that need the structured webhook
500
+ * grouping should call `listWebhooks` directly.
501
+ */
502
+ function listAllOperations(parsed, diagnostics) {
503
+ const seenIds = /* @__PURE__ */ new Map();
504
+ const pathOps = listOperations(parsed, diagnostics, seenIds);
505
+ const webhookOps = listWebhooks(parsed, diagnostics, seenIds).flatMap((w) => w.operations);
506
+ return [...pathOps, ...webhookOps];
507
+ }
482
508
  function getExternalDocs(obj) {
483
509
  const docs = getProperty(obj, "externalDocs");
484
510
  if (!isObject(docs)) return void 0;
@@ -559,4 +585,4 @@ function getLinks(parsed, path, method, statusCode, diagnostics) {
559
585
  return result;
560
586
  }
561
587
  //#endregion
562
- export { getExternalDocs, getLinks, getParameters, getRequestBody, getResponseHeaders, getResponses, getSchema, getSecurityRequirements, getSecuritySchemes, getXmlInfo, listCallbacks, listOperations, listWebhooks, parseOpenApiDocument };
588
+ export { getExternalDocs, getLinks, getParameters, getRequestBody, getResponseHeaders, getResponses, getSchema, getSecurityRequirements, getSecuritySchemes, getXmlInfo, listAllOperations, listCallbacks, listOperations, listWebhooks, parseOpenApiDocument };
@@ -1,4 +1,4 @@
1
- import { i as DiagnosticsOptions } from "../diagnostics-BS2kaUyE.mjs";
1
+ import { i as DiagnosticsOptions } from "../diagnostics-Cbwak-ZX.mjs";
2
2
  import { OpenApiDocument, OperationInfo, ParameterInfo, ResponseInfo, getRequestBody } from "./parser.mjs";
3
3
 
4
4
  //#region src/openapi/resolve.d.ts
@@ -5,7 +5,7 @@ import { isPrototypePollutingKey } from "../core/uri.mjs";
5
5
  import { detectOpenApiVersion } from "../core/version.mjs";
6
6
  import { o as normaliseOpenApiSchemas, r as documentContainsKeyword } from "../normalise-DCYp06Sr.mjs";
7
7
  import { resolveRefChain } from "../core/refChain.mjs";
8
- import { getParameters, getRequestBody, getResponses, listOperations, listWebhooks, parseOpenApiDocument } from "./parser.mjs";
8
+ import { getParameters, getRequestBody, getResponses, listAllOperations, parseOpenApiDocument } from "./parser.mjs";
9
9
  //#region src/openapi/resolve.ts
10
10
  /**
11
11
  * OpenAPI document resolution and caching.
@@ -325,7 +325,7 @@ function extractPathItemInfo(pathItem) {
325
325
  */
326
326
  function resolveOperationFromParsed(parsed, path, method, diagnostics) {
327
327
  const pathItemNode = lookupPathItemNode(parsed, path, diagnostics);
328
- const operation = [...listOperations(parsed), ...listWebhooks(parsed).flatMap((w) => w.operations)].find((op) => op.path === path && op.method === method);
328
+ const operation = listAllOperations(parsed).find((op) => op.path === path && op.method === method);
329
329
  if (operation === void 0) throw new Error(`Operation not found: ${method.toUpperCase()} ${path}`);
330
330
  if (pathItemNode === void 0) throw new Error(`Path item missing for ${method.toUpperCase()} ${path}`);
331
331
  return {
@@ -1,5 +1,5 @@
1
1
  import { d as FieldOverrides, j as WalkedField, u as FieldOverride, w as SchemaMeta } from "../types-BTB73MB8.mjs";
2
- import { t as Diagnostic } from "../diagnostics-BS2kaUyE.mjs";
2
+ import { t as Diagnostic } from "../diagnostics-Cbwak-ZX.mjs";
3
3
  import { t as SchemaError } from "../errors-g_MCTQel.mjs";
4
4
  import { l as RenderProps, r as ComponentResolver } from "../renderer-CXJ8y0qw.mjs";
5
5
  import { FromJSONSchema, FromJSONSchemaMode, IsSwagger2Doc, PathOfType, RejectUnrepresentableZod, ResolveOpenAPIRef, TypeAtPath, __SchemaInferenceFellBack } from "../core/typeInference.mjs";
@@ -135,7 +135,7 @@ interface SchemaComponentProps<T = unknown, Ref extends string | undefined = und
135
135
  *
136
136
  * TODO(round7-integration): promote to
137
137
  * `NarrowAtPath<InferSchemaValue<T, Ref, "output">, P>` once the
138
- * round-7 test fixtures (headless union, discriminated union,
138
+ * test fixtures (headless union, discriminated union,
139
139
  * schemaview equivalence, type-inference issue fixes) are
140
140
  * migrated to either narrow their fixtures or accept the loose
141
141
  * boundary. The retype cascades through call sites that
@@ -1,5 +1,5 @@
1
1
  import { w as SchemaMeta } from "../types-BTB73MB8.mjs";
2
- import { t as Diagnostic } from "../diagnostics-BS2kaUyE.mjs";
2
+ import { t as Diagnostic } from "../diagnostics-Cbwak-ZX.mjs";
3
3
  import { r as ComponentResolver } from "../renderer-CXJ8y0qw.mjs";
4
4
  import { RejectUnrepresentableZod } from "../core/typeInference.mjs";
5
5
  import { WidgetMap } from "./SchemaComponent.mjs";
@@ -1,4 +1,4 @@
1
- import { i as DiagnosticsOptions } from "./diagnostics-BS2kaUyE.mjs";
1
+ import { i as DiagnosticsOptions } from "./diagnostics-Cbwak-ZX.mjs";
2
2
 
3
3
  //#region src/core/ref.d.ts
4
4
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "schema-components",
3
- "version": "1.23.0",
3
+ "version": "1.24.0",
4
4
  "description": "React components that render UI from Zod schemas, JSON Schema, and OpenAPI documents",
5
5
  "type": "module",
6
6
  "exports": {