schema-components 1.29.0 → 2.0.1
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/README.md +38 -16
- package/dist/core/adapter.d.mts +213 -3
- package/dist/core/adapter.mjs +1 -1
- package/dist/core/constraintHint.d.mts +15 -0
- package/dist/core/constraintHint.mjs +24 -0
- package/dist/core/constraints.d.mts +2 -2
- package/dist/core/constraints.mjs +1 -1
- package/dist/core/diagnostics.d.mts +1 -1
- package/dist/core/errors.d.mts +1 -1
- package/dist/core/fieldOrder.d.mts +1 -1
- package/dist/core/formats.d.mts +1 -1
- package/dist/core/idPath.d.mts +35 -5
- package/dist/core/idPath.mjs +79 -7
- package/dist/core/inferValue.d.mts +2 -0
- package/dist/core/inferValue.mjs +1 -0
- package/dist/core/limits.d.mts +1 -1
- package/dist/core/limits.mjs +5 -0
- package/dist/core/merge.d.mts +12 -1
- package/dist/core/merge.mjs +66 -3
- package/dist/core/normalise.d.mts +1 -1
- package/dist/core/normalise.mjs +1 -1
- package/dist/core/openapi30.mjs +1 -1
- package/dist/core/ref.d.mts +1 -1
- package/dist/core/refChain.d.mts +3 -4
- package/dist/core/refChain.mjs +2 -3
- package/dist/core/renderer.d.mts +199 -2
- package/dist/core/swagger2.d.mts +1 -1
- package/dist/core/swagger2.mjs +1 -1
- package/dist/core/typeInference.d.mts +3 -3
- package/dist/core/types.d.mts +1 -1
- package/dist/core/unionMatch.d.mts +1 -1
- package/dist/core/uri.d.mts +12 -4
- package/dist/core/uri.mjs +30 -4
- package/dist/core/walkBuilders.d.mts +18 -6
- package/dist/core/walkBuilders.mjs +3 -1
- package/dist/core/walker.d.mts +1 -1
- package/dist/core/walker.mjs +5 -0
- package/dist/{diagnostics-ByEzkjrA.d.mts → diagnostics-BTrm3O6J.d.mts} +1 -1
- package/dist/{errors-D8JndRwI.d.mts → errors-Dki7tji4.d.mts} +1 -1
- package/dist/html/a11y.d.mts +3 -7
- package/dist/html/a11y.mjs +1 -16
- package/dist/html/renderToHtml.d.mts +22 -9
- package/dist/html/renderToHtml.mjs +2 -1
- package/dist/html/renderToHtmlStream.d.mts +24 -11
- package/dist/html/renderToHtmlStream.mjs +2 -1
- package/dist/html/renderers.d.mts +2 -33
- package/dist/html/renderers.mjs +39 -91
- package/dist/html/streamRenderers.d.mts +3 -3
- package/dist/html/streamRenderers.mjs +13 -8
- package/dist/inferValue-PPXWJpbN.d.mts +77 -0
- package/dist/{limits-DswmqWuy.d.mts → limits-x4OiyJxh.d.mts} +5 -0
- package/dist/{normalise-Db1xaxgx.mjs → normalise-DB-Xtjmn.mjs} +43 -2
- package/dist/openapi/ApiCallbacks.d.mts +1 -1
- package/dist/openapi/ApiLinks.d.mts +1 -1
- package/dist/openapi/ApiResponseHeaders.d.mts +1 -1
- package/dist/openapi/ApiSecurity.d.mts +1 -1
- package/dist/openapi/ApiSecurity.mjs +21 -8
- package/dist/openapi/bundle.d.mts +31 -0
- package/dist/openapi/components.d.mts +41 -10
- package/dist/openapi/components.mjs +19 -13
- package/dist/openapi/parser.d.mts +13 -13
- package/dist/openapi/parser.mjs +12 -12
- package/dist/openapi/resolve.d.mts +38 -49
- package/dist/openapi/resolve.mjs +62 -56
- package/dist/react/SchemaComponent.d.mts +19 -95
- package/dist/react/SchemaComponent.mjs +12 -1
- package/dist/react/SchemaView.d.mts +11 -7
- package/dist/react/SchemaView.mjs +3 -1
- package/dist/react/a11y.d.mts +74 -7
- package/dist/react/a11y.mjs +67 -6
- package/dist/react/fieldPath.d.mts +16 -1
- package/dist/react/fieldPath.mjs +25 -1
- package/dist/react/fieldShell.d.mts +49 -0
- package/dist/react/fieldShell.mjs +37 -0
- package/dist/react/headless.d.mts +1 -1
- package/dist/react/headlessRenderers.d.mts +2 -2
- package/dist/react/headlessRenderers.mjs +123 -54
- package/dist/{ref-CPh8rKQ3.d.mts → ref-DdsbekXX.d.mts} +33 -1
- package/dist/themes/mantine.d.mts +36 -20
- package/dist/themes/mantine.mjs +179 -150
- package/dist/themes/mui.d.mts +47 -21
- package/dist/themes/mui.mjs +259 -222
- package/dist/themes/radix.d.mts +38 -23
- package/dist/themes/radix.mjs +208 -180
- package/dist/themes/shadcn.d.mts +6 -3
- package/dist/themes/shadcn.mjs +93 -93
- package/dist/{types-C2Ay1FEh.d.mts → types-BrYbjC7_.d.mts} +7 -0
- package/package.json +5 -1
- package/dist/adapter-DcWi4XXn.d.mts +0 -223
- package/dist/renderer-OaOz-n6-.d.mts +0 -185
package/README.md
CHANGED
|
@@ -298,14 +298,20 @@ import { shadcnResolver } from "schema-components/themes/shadcn";
|
|
|
298
298
|
### MUI
|
|
299
299
|
|
|
300
300
|
```tsx
|
|
301
|
-
import {
|
|
302
|
-
import {
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
301
|
+
import { SchemaProvider } from "schema-components/react/SchemaComponent";
|
|
302
|
+
import { createMuiResolver } from "schema-components/themes/mui";
|
|
303
|
+
import TextField from "@mui/material/TextField";
|
|
304
|
+
import Checkbox from "@mui/material/Checkbox";
|
|
305
|
+
import Typography from "@mui/material/Typography";
|
|
306
|
+
import Box from "@mui/material/Box";
|
|
307
|
+
import MenuItem from "@mui/material/MenuItem";
|
|
308
|
+
import FormControlLabel from "@mui/material/FormControlLabel";
|
|
309
|
+
|
|
310
|
+
const muiResolver = createMuiResolver({
|
|
311
|
+
TextField, Checkbox, Typography, Box, MenuItem, FormControlLabel,
|
|
312
|
+
});
|
|
306
313
|
|
|
307
|
-
|
|
308
|
-
<SchemaProvider resolver={shadcnResolver}>
|
|
314
|
+
<SchemaProvider resolver={muiResolver}>
|
|
309
315
|
<SchemaComponent schema={userSchema} value={user} onChange={setUser} />
|
|
310
316
|
</SchemaProvider>
|
|
311
317
|
```
|
|
@@ -313,12 +319,17 @@ registerMuiComponents();
|
|
|
313
319
|
### Mantine
|
|
314
320
|
|
|
315
321
|
```tsx
|
|
316
|
-
import {
|
|
317
|
-
import {
|
|
322
|
+
import { SchemaProvider } from "schema-components/react/SchemaComponent";
|
|
323
|
+
import { createMantineResolver } from "schema-components/themes/mantine";
|
|
324
|
+
import {
|
|
325
|
+
TextInput, NumberInput, Switch, Select, Fieldset, Text,
|
|
326
|
+
} from "@mantine/core";
|
|
318
327
|
|
|
319
|
-
|
|
328
|
+
const mantineResolver = createMantineResolver({
|
|
329
|
+
TextInput, NumberInput, Switch, Select, Fieldset, Text,
|
|
330
|
+
});
|
|
320
331
|
|
|
321
|
-
<SchemaProvider resolver={
|
|
332
|
+
<SchemaProvider resolver={mantineResolver}>
|
|
322
333
|
<SchemaComponent schema={userSchema} value={user} onChange={setUser} />
|
|
323
334
|
</SchemaProvider>
|
|
324
335
|
```
|
|
@@ -326,12 +337,23 @@ registerMantineComponents();
|
|
|
326
337
|
### Radix Themes
|
|
327
338
|
|
|
328
339
|
```tsx
|
|
329
|
-
import {
|
|
330
|
-
import {
|
|
331
|
-
|
|
332
|
-
|
|
340
|
+
import { SchemaProvider } from "schema-components/react/SchemaComponent";
|
|
341
|
+
import { createRadixResolver } from "schema-components/themes/radix";
|
|
342
|
+
import { Box, Checkbox, Flex, Select, Text, TextField } from "@radix-ui/themes";
|
|
343
|
+
|
|
344
|
+
const radixResolver = createRadixResolver({
|
|
345
|
+
Box,
|
|
346
|
+
Checkbox,
|
|
347
|
+
Flex,
|
|
348
|
+
SelectRoot: Select.Root,
|
|
349
|
+
SelectTrigger: Select.Trigger,
|
|
350
|
+
SelectContent: Select.Content,
|
|
351
|
+
SelectItem: Select.Item,
|
|
352
|
+
Text,
|
|
353
|
+
TextField: TextField.Root,
|
|
354
|
+
});
|
|
333
355
|
|
|
334
|
-
<SchemaProvider resolver={
|
|
356
|
+
<SchemaProvider resolver={radixResolver}>
|
|
335
357
|
<SchemaComponent schema={userSchema} value={user} onChange={setUser} />
|
|
336
358
|
</SchemaProvider>
|
|
337
359
|
```
|
package/dist/core/adapter.d.mts
CHANGED
|
@@ -1,3 +1,213 @@
|
|
|
1
|
-
import { m as JsonObject, w as SchemaMeta } from "../types-
|
|
2
|
-
import {
|
|
3
|
-
|
|
1
|
+
import { m as JsonObject, w as SchemaMeta } from "../types-BrYbjC7_.mjs";
|
|
2
|
+
import { i as DiagnosticsOptions } from "../diagnostics-BTrm3O6J.mjs";
|
|
3
|
+
|
|
4
|
+
//#region src/core/adapter.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* Classification produced by {@link detectSchemaKind} when inspecting a
|
|
7
|
+
* runtime schema input.
|
|
8
|
+
*
|
|
9
|
+
* @group Adapter
|
|
10
|
+
*/
|
|
11
|
+
type SchemaKind = "zod4" | "zod3" | "jsonSchema" | "openapi" | "unsupported-schema-lib";
|
|
12
|
+
/**
|
|
13
|
+
* Classify a runtime schema input by structural markers — Zod 4, Zod 3,
|
|
14
|
+
* OpenAPI document, plain JSON Schema, or an unsupported third-party
|
|
15
|
+
* schema library.
|
|
16
|
+
*
|
|
17
|
+
* - `zod4` — has a `_zod` marker (further validation that `_zod.def` is a
|
|
18
|
+
* non-null object happens inside `normaliseZod4`).
|
|
19
|
+
* - `zod3` — has `_def` and no `_zod`. The `typeName` field is no longer
|
|
20
|
+
* required: any `_def` without `_zod` is treated as a probable Zod 3
|
|
21
|
+
* schema. Third-party libraries that expose `_def` without `_zod` are
|
|
22
|
+
* nearly always Zod 3 forks; surfacing the migration message is the
|
|
23
|
+
* correct response.
|
|
24
|
+
* - `openapi` — has `openapi` or `swagger` at the root.
|
|
25
|
+
* - `unsupported-schema-lib` — has `parse` and `safeParse` callables but
|
|
26
|
+
* no `_zod` and no `_def` marker. This catches Standard Schema
|
|
27
|
+
* implementations (valibot, arktype, etc.) that would otherwise flow
|
|
28
|
+
* through as "malformed JSON Schema".
|
|
29
|
+
* - `jsonSchema` — fallback for anything that does not match the above.
|
|
30
|
+
*
|
|
31
|
+
* @group Adapter
|
|
32
|
+
*/
|
|
33
|
+
declare function detectSchemaKind(input: unknown): SchemaKind;
|
|
34
|
+
/**
|
|
35
|
+
* Wraps z.toJSONSchema() for a runtime-validated Zod schema.
|
|
36
|
+
*
|
|
37
|
+
* The _zod guard in normaliseZod4 has confirmed this is a valid Zod schema,
|
|
38
|
+
* but TypeScript cannot represent "has _zod.def" as the $ZodType parameter
|
|
39
|
+
* that z.toJSONSchema expects. This is the library boundary equivalent of
|
|
40
|
+
* object → Record<string, unknown> — the type mismatch is genuinely unavoidable.
|
|
41
|
+
*
|
|
42
|
+
* # Options
|
|
43
|
+
*
|
|
44
|
+
* `z.toJSONSchema` is invoked with an explicit options object rather than
|
|
45
|
+
* Zod's defaults so the conversion contract is pinned and stable:
|
|
46
|
+
*
|
|
47
|
+
* - `target: "draft-2020-12"` — matches the walker's draft target.
|
|
48
|
+
* - `unrepresentable: "throw"` — keeps the unrepresentable-type rules in
|
|
49
|
+
* the classifier table firing instead of silently emitting `{}`.
|
|
50
|
+
* - `cycles: "ref"` — converts cyclic graphs into $ref pairs rather than
|
|
51
|
+
* throwing. Cycles in user schemas surface through the walker's $ref
|
|
52
|
+
* resolution rather than the adapter.
|
|
53
|
+
* - `io` — selects which side of every transform / pipe / codec is
|
|
54
|
+
* converted. Defaults to `"output"` (the OUTPUT side); pass `"input"`
|
|
55
|
+
* to render the INPUT side instead. The input side is invisible to
|
|
56
|
+
* the converted schema when `io: "output"` is in force, even though
|
|
57
|
+
* `safeParse` on the same Zod schema consumes the input shape. For
|
|
58
|
+
* transforms this divergence is fatal and the call throws via
|
|
59
|
+
* `Transforms cannot be represented`; for `z.codec(...)` the call
|
|
60
|
+
* succeeds but only the selected side is rendered. Consumers receive
|
|
61
|
+
* a `zod-codec-output-only` diagnostic in the codec case so the
|
|
62
|
+
* asymmetry is visible — see `screenPreConversion`.
|
|
63
|
+
*
|
|
64
|
+
* # Error classification
|
|
65
|
+
*
|
|
66
|
+
* Any exception thrown by z.toJSONSchema is classified into a
|
|
67
|
+
* SchemaNormalisationError so the caller does not have to re-parse error
|
|
68
|
+
* message strings. The classification covers:
|
|
69
|
+
*
|
|
70
|
+
* - Nested Zod 3 schemas inside a Zod 4 tree → zod3-unsupported.
|
|
71
|
+
* Detected structurally (presence of `_def.typeName` markers anywhere
|
|
72
|
+
* in the schema tree) so the check works across V8, JavaScriptCore,
|
|
73
|
+
* and SpiderMonkey, none of which agree on the wording of
|
|
74
|
+
* "Cannot read properties of undefined".
|
|
75
|
+
* - Transforms → zod-transform-unsupported. This also catches `z.codec(…)`
|
|
76
|
+
* because Zod implements codecs as a pipe + transform internally, so
|
|
77
|
+
* they trip the same processor when round-tripping is forced. (Plain
|
|
78
|
+
* `z.toJSONSchema(codec)` itself does NOT throw because Zod picks one
|
|
79
|
+
* side of the codec; the static rejection in `typeInference.ts` is the
|
|
80
|
+
* compile-time guard.)
|
|
81
|
+
* - Dynamic catch values whose handler throws → zod-type-unrepresentable
|
|
82
|
+
* with zodType "dynamic-catch".
|
|
83
|
+
* - Unrepresentable types — bigint, date, map, set, symbol, function, custom,
|
|
84
|
+
* undefined, void, NaN, and the literal-only forms `z.literal(undefined)`
|
|
85
|
+
* ("undefined-literal") and `z.literal(<bigint>)` ("bigint-literal") →
|
|
86
|
+
* zod-type-unrepresentable.
|
|
87
|
+
* - The catch-all "Non-representable type encountered: <type>" fallback Zod
|
|
88
|
+
* emits for any new schema kind without a registered processor →
|
|
89
|
+
* zod-type-unrepresentable with zodType set to the offending def.type.
|
|
90
|
+
* - Cycle detected (`cycles: "throw"`) → zod-cycle-detected.
|
|
91
|
+
* - Duplicate schema id → zod-duplicate-id.
|
|
92
|
+
* - "Unprocessed schema. This is a bug in Zod." → zod-conversion-bug.
|
|
93
|
+
* - "Error converting schema to JSON." → zod-conversion-failed (explicit
|
|
94
|
+
* classification rather than the generic fallback so the contract test
|
|
95
|
+
* protects the prefix from drift).
|
|
96
|
+
* - Anything else → zod-conversion-failed.
|
|
97
|
+
*
|
|
98
|
+
* The original error is preserved on each classified error via the `cause`
|
|
99
|
+
* field so consumers can still inspect the Zod stack trace.
|
|
100
|
+
*/
|
|
101
|
+
/**
|
|
102
|
+
* Direction of the Zod transform / pipe / codec that
|
|
103
|
+
* {@link normaliseSchema} should surface to the renderer.
|
|
104
|
+
*
|
|
105
|
+
* - `"output"` (default) — the server-facing side of every transform,
|
|
106
|
+
* matching `z.toJSONSchema`'s default and the historic adapter
|
|
107
|
+
* behaviour.
|
|
108
|
+
* - `"input"` — the client-facing side; flips a `z.codec(...)` chain
|
|
109
|
+
* so consumers can render its input shape.
|
|
110
|
+
*
|
|
111
|
+
* @group Adapter
|
|
112
|
+
*/
|
|
113
|
+
type SchemaIoSide = "input" | "output";
|
|
114
|
+
/**
|
|
115
|
+
* True when `value` is a Zod schema implemented as a codec
|
|
116
|
+
* (`z.codec(...)`). Detection looks for the `$ZodCodec` marker on the
|
|
117
|
+
* schema's `_zod.traits` Set — the same structural check used by Zod
|
|
118
|
+
* itself in `to-json-schema.ts`'s `isTransforming` helper.
|
|
119
|
+
*
|
|
120
|
+
* Promoted from a duplicated local helper in `react/SchemaComponent.tsx`
|
|
121
|
+
* so the validation boundary inside `runValidation` can branch on
|
|
122
|
+
* codec-vs-not-codec without re-implementing the trait check. The
|
|
123
|
+
* shared helper anchors a single source of truth for codec detection:
|
|
124
|
+
* any future change to Zod's trait naming flows through here, not
|
|
125
|
+
* through two parallel copies.
|
|
126
|
+
*
|
|
127
|
+
* Returns `false` for non-objects, plain JSON Schema inputs, OpenAPI
|
|
128
|
+
* documents, or Zod schemas of any other kind. This is structural
|
|
129
|
+
* rather than nominal — a Zod 4 codec produced by any path that ends
|
|
130
|
+
* up tagging `_zod.traits` with `$ZodCodec` is recognised, including
|
|
131
|
+
* schemas wrapped by user-defined helpers.
|
|
132
|
+
*/
|
|
133
|
+
declare function isCodecSchema(value: unknown): boolean;
|
|
134
|
+
/**
|
|
135
|
+
* Exposed for unit testing — lets the contract test enumerate every rule's
|
|
136
|
+
* `prefix` value and assert mutual non-prefixing.
|
|
137
|
+
*/
|
|
138
|
+
declare const __CLASSIFIER_RULES_FOR_TEST: readonly {
|
|
139
|
+
readonly prefix: string;
|
|
140
|
+
}[];
|
|
141
|
+
/**
|
|
142
|
+
* Result of {@link normaliseSchema}. Carries the canonical Draft 2020-12
|
|
143
|
+
* JSON Schema the walker consumes, the optional original Zod schema
|
|
144
|
+
* (used for validation), and the resolved root document so cross-document
|
|
145
|
+
* `$ref`s can be dereferenced downstream.
|
|
146
|
+
*
|
|
147
|
+
* @group Adapter
|
|
148
|
+
*/
|
|
149
|
+
interface NormalisedSchema {
|
|
150
|
+
/** JSON Schema object — the authoritative schema for rendering. */
|
|
151
|
+
jsonSchema: JsonObject;
|
|
152
|
+
/** Original Zod schema, if input was Zod. Used for validation. */
|
|
153
|
+
zodSchema?: unknown;
|
|
154
|
+
/** Root-level metadata. */
|
|
155
|
+
rootMeta: SchemaMeta | undefined;
|
|
156
|
+
/** The root document for $ref resolution. */
|
|
157
|
+
rootDocument: JsonObject;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Options accepted by {@link normaliseSchema}.
|
|
161
|
+
*
|
|
162
|
+
* @group Adapter
|
|
163
|
+
*/
|
|
164
|
+
interface NormaliseOptions {
|
|
165
|
+
/** Diagnostics channel for surfacing silent fallbacks. */
|
|
166
|
+
diagnostics?: DiagnosticsOptions;
|
|
167
|
+
/**
|
|
168
|
+
* Side of every transform / pipe / codec to render. Defaults to
|
|
169
|
+
* `"output"`, matching `z.toJSONSchema`'s default and the
|
|
170
|
+
* historic behaviour of the adapter. Passing `"input"` flips the
|
|
171
|
+
* conversion so consumers rendering the input shape of a
|
|
172
|
+
* `z.codec(...)` chain receive that side instead of the output
|
|
173
|
+
* side. Only the Zod 4 branch consults this option — JSON Schema
|
|
174
|
+
* and OpenAPI inputs are already a single canonical shape.
|
|
175
|
+
*/
|
|
176
|
+
io?: SchemaIoSide;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Normalise any supported schema input — Zod 4 schema, plain JSON
|
|
180
|
+
* Schema (any draft), Swagger 2.0, OpenAPI 3.0 or 3.1 document — into
|
|
181
|
+
* a canonical Draft 2020-12 {@link NormalisedSchema} the walker can
|
|
182
|
+
* consume.
|
|
183
|
+
*
|
|
184
|
+
* Dispatches on {@link detectSchemaKind}, applies the appropriate
|
|
185
|
+
* version normaliser, and returns the JSON Schema alongside the
|
|
186
|
+
* original Zod schema (for validation) and the resolved root document
|
|
187
|
+
* (for cross-document `$ref` resolution). Throws
|
|
188
|
+
* `SchemaNormalisationError` for unsupported inputs (Zod 3, valibot,
|
|
189
|
+
* arktype, codec or other unrepresentable Zod types).
|
|
190
|
+
*
|
|
191
|
+
* @group Adapter
|
|
192
|
+
*/
|
|
193
|
+
declare function normaliseSchema(input: unknown, ref?: string, options?: NormaliseOptions): NormalisedSchema;
|
|
194
|
+
/**
|
|
195
|
+
* Surface root-level metadata from the JSON Schema into the `rootMeta`
|
|
196
|
+
* shape consumed by the walker. Pulls `readOnly`, `writeOnly`,
|
|
197
|
+
* `description`, `title`, `deprecated`, `examples`, and `default`
|
|
198
|
+
* directly from the schema root.
|
|
199
|
+
*
|
|
200
|
+
* `examples` is forwarded only when present as an array (per JSON Schema
|
|
201
|
+
* Draft 2020-12 — Draft 04's `example` singular is normalised upstream).
|
|
202
|
+
* `default` is forwarded for any value the schema declares (any JSON
|
|
203
|
+
* value, including `null` and `false`); the presence check uses `in`
|
|
204
|
+
* so a literal `false` or `null` default is preserved.
|
|
205
|
+
*
|
|
206
|
+
* `examples` and `default` ride on the `[key: string]: unknown` index
|
|
207
|
+
* signature of {@link SchemaMeta}. They are not declared as named fields
|
|
208
|
+
* on `SchemaMeta` because that type lives in `types.ts` and is shared
|
|
209
|
+
* with the walker; the index signature is the agreed extension point.
|
|
210
|
+
*/
|
|
211
|
+
declare function extractRootMetaFromJson(jsonSchema: JsonObject): SchemaMeta | undefined;
|
|
212
|
+
//#endregion
|
|
213
|
+
export { type JsonObject, NormaliseOptions, NormalisedSchema, SchemaIoSide, SchemaKind, type SchemaMeta, __CLASSIFIER_RULES_FOR_TEST, detectSchemaKind, extractRootMetaFromJson, isCodecSchema, normaliseSchema };
|
package/dist/core/adapter.mjs
CHANGED
|
@@ -4,7 +4,7 @@ import { SchemaNormalisationError } from "./errors.mjs";
|
|
|
4
4
|
import { appendPointer, emitDiagnostic } from "./diagnostics.mjs";
|
|
5
5
|
import { dereference } from "./ref.mjs";
|
|
6
6
|
import { detectOpenApiVersion, inferJsonSchemaDraftWithReason, isSwagger2, matchJsonSchemaDraftUri } from "./version.mjs";
|
|
7
|
-
import { a as normaliseJsonSchema$1, o as normaliseOpenApiSchemas } from "../normalise-
|
|
7
|
+
import { a as normaliseJsonSchema$1, o as normaliseOpenApiSchemas } from "../normalise-DB-Xtjmn.mjs";
|
|
8
8
|
import { z } from "zod";
|
|
9
9
|
//#region src/core/adapter.ts
|
|
10
10
|
/**
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { AllConstraints } from "./renderer.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/core/constraintHint.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* Build a human-readable constraint description string.
|
|
6
|
+
*
|
|
7
|
+
* Returns `undefined` when no constraint worth announcing is present.
|
|
8
|
+
* Pattern hints are suppressed when a `format` is set because the
|
|
9
|
+
* format already implies the pattern and the resulting copy would be
|
|
10
|
+
* misleading ("Must match pattern" alongside a `format: "email"` field
|
|
11
|
+
* would read as if the schema required a non-email regex).
|
|
12
|
+
*/
|
|
13
|
+
declare function constraintHint(c: AllConstraints): string | undefined;
|
|
14
|
+
//#endregion
|
|
15
|
+
export { constraintHint };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
//#region src/core/constraintHint.ts
|
|
2
|
+
/**
|
|
3
|
+
* Build a human-readable constraint description string.
|
|
4
|
+
*
|
|
5
|
+
* Returns `undefined` when no constraint worth announcing is present.
|
|
6
|
+
* Pattern hints are suppressed when a `format` is set because the
|
|
7
|
+
* format already implies the pattern and the resulting copy would be
|
|
8
|
+
* misleading ("Must match pattern" alongside a `format: "email"` field
|
|
9
|
+
* would read as if the schema required a non-email regex).
|
|
10
|
+
*/
|
|
11
|
+
function constraintHint(c) {
|
|
12
|
+
const parts = [];
|
|
13
|
+
if (c.minLength !== void 0) parts.push(`Minimum ${String(c.minLength)} characters`);
|
|
14
|
+
if (c.maxLength !== void 0) parts.push(`Maximum ${String(c.maxLength)} characters`);
|
|
15
|
+
if (c.minimum !== void 0) parts.push(`Minimum ${String(c.minimum)}`);
|
|
16
|
+
if (c.maximum !== void 0) parts.push(`Maximum ${String(c.maximum)}`);
|
|
17
|
+
if (c.pattern !== void 0 && c.format === void 0) parts.push("Must match pattern");
|
|
18
|
+
if (c.minItems !== void 0) parts.push(`Minimum ${String(c.minItems)} items`);
|
|
19
|
+
if (c.maxItems !== void 0) parts.push(`Maximum ${String(c.maxItems)} items`);
|
|
20
|
+
if (parts.length === 0) return void 0;
|
|
21
|
+
return parts.join(". ");
|
|
22
|
+
}
|
|
23
|
+
//#endregion
|
|
24
|
+
export { constraintHint };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { E as StringConstraints, f as FileConstraints, t as ArrayConstraints, x as ObjectConstraints, y as NumberConstraints } from "../types-
|
|
2
|
-
import { i as DiagnosticsOptions } from "../diagnostics-
|
|
1
|
+
import { E as StringConstraints, f as FileConstraints, t as ArrayConstraints, x as ObjectConstraints, y as NumberConstraints } from "../types-BrYbjC7_.mjs";
|
|
2
|
+
import { i as DiagnosticsOptions } from "../diagnostics-BTrm3O6J.mjs";
|
|
3
3
|
|
|
4
4
|
//#region src/core/constraints.d.ts
|
|
5
5
|
/**
|
|
@@ -30,7 +30,7 @@ function extractStringConstraints(schema, diagnostics, pointer = "") {
|
|
|
30
30
|
c.format = format;
|
|
31
31
|
const pattern = FORMAT_PATTERNS[format];
|
|
32
32
|
if (pattern !== void 0) c.formatPattern = pattern;
|
|
33
|
-
else if (format !== "binary") emitDiagnostic(diagnostics, {
|
|
33
|
+
else if (format !== "binary" && format !== "password") emitDiagnostic(diagnostics, {
|
|
34
34
|
code: "unknown-format",
|
|
35
35
|
message: `Unknown format: ${format}`,
|
|
36
36
|
pointer,
|
|
@@ -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-
|
|
1
|
+
import { a as appendPointer, i as DiagnosticsOptions, n as DiagnosticCode, o as emitDiagnostic, r as DiagnosticSink, t as Diagnostic } from "../diagnostics-BTrm3O6J.mjs";
|
|
2
2
|
export { Diagnostic, DiagnosticCode, DiagnosticSink, DiagnosticsOptions, appendPointer, emitDiagnostic };
|
package/dist/core/errors.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { i as SchemaRenderError, n as SchemaFieldError, r as SchemaNormalisationError, t as SchemaError } from "../errors-
|
|
1
|
+
import { i as SchemaRenderError, n as SchemaFieldError, r as SchemaNormalisationError, t as SchemaError } from "../errors-Dki7tji4.mjs";
|
|
2
2
|
export { SchemaError, SchemaFieldError, SchemaNormalisationError, SchemaRenderError };
|
package/dist/core/formats.d.mts
CHANGED
package/dist/core/idPath.d.mts
CHANGED
|
@@ -21,16 +21,46 @@
|
|
|
21
21
|
* Whitelist (not blacklist) so unexpected characters from free-text sources
|
|
22
22
|
* — `meta.description`, label-derived suffixes, encoded JSON Pointers —
|
|
23
23
|
* cannot leak into ids and break CSS selectors or aria associations.
|
|
24
|
+
*
|
|
25
|
+
* Non-ASCII inputs (e.g. CJK property names like `名前`, accented Latin
|
|
26
|
+
* like `café`, emoji like `🦄`) collapse under the whitelist to a short
|
|
27
|
+
* or empty string and would silently collide on `sc-`. To keep ids
|
|
28
|
+
* deterministic AND unique per input, the normaliser appends a short
|
|
29
|
+
* hash suffix derived from the original string whenever the whitelisted
|
|
30
|
+
* collapse:
|
|
31
|
+
*
|
|
32
|
+
* - produces an empty string, OR
|
|
33
|
+
* - dropped non-structural characters from the input (i.e. anything
|
|
34
|
+
* besides the path joiners `.`, `[`, `]` and ASCII whitespace).
|
|
35
|
+
*
|
|
36
|
+
* Structural separator runs do NOT trigger the disambiguator so
|
|
37
|
+
* canonical paths like `user.preferences` and `tags[0]` keep their
|
|
38
|
+
* historic readable form (`user-preferences`, `tags-0`).
|
|
39
|
+
*
|
|
40
|
+
* The hash is a 32-bit FNV-1a variant rendered in base-36. It is
|
|
41
|
+
* deterministic (same input → same output), short (≤ 7 characters), and
|
|
42
|
+
* non-cryptographic — collision resistance is good enough for DOM ids,
|
|
43
|
+
* and a cryptographic primitive is unnecessary and not universally
|
|
44
|
+
* available (no `crypto` global in every JS runtime that consumes the
|
|
45
|
+
* library).
|
|
46
|
+
*
|
|
47
|
+
* The leading character is guaranteed to be an ASCII letter so the full
|
|
48
|
+
* `sc-<segment>` id is always a valid CSS identifier and `querySelector`
|
|
49
|
+
* target. Empty-collapse inputs receive a synthetic `u` (for "unicode")
|
|
50
|
+
* prefix on the hash so the id never starts with a digit.
|
|
24
51
|
*/
|
|
25
52
|
declare function normaliseIdSegment(value: string): string;
|
|
26
53
|
/**
|
|
27
|
-
* Build the canonical `sc-`-prefixed DOM id for a structural path.
|
|
28
|
-
*
|
|
54
|
+
* Build the canonical `sc-`-prefixed DOM id for a structural path. Use
|
|
55
|
+
* this as the base id for an input element; derived ids (panel, tab,
|
|
29
56
|
* hint) compose suffixes onto the returned string.
|
|
30
57
|
*
|
|
31
|
-
*
|
|
32
|
-
*
|
|
33
|
-
*
|
|
58
|
+
* An empty `path` is permitted — it surfaces as the bare prefix `sc-`
|
|
59
|
+
* so a leaf renderer at the schema root (e.g.
|
|
60
|
+
* `renderToHtml(z.string())`) still emits a usable id without throwing.
|
|
61
|
+
* Container renderers always thread a non-empty path through
|
|
62
|
+
* `renderChild`, so the empty-id case can never produce sibling
|
|
63
|
+
* collisions inside a structured form.
|
|
34
64
|
*/
|
|
35
65
|
declare function fieldDomId(path: string): string;
|
|
36
66
|
/**
|
package/dist/core/idPath.mjs
CHANGED
|
@@ -15,6 +15,17 @@ import "./cssClasses.mjs";
|
|
|
15
15
|
* Pipelines should import the helpers below rather than re-deriving them.
|
|
16
16
|
*/
|
|
17
17
|
/**
|
|
18
|
+
* Characters the path joiners (`react/SchemaComponent.joinPath`,
|
|
19
|
+
* `html/a11y.joinPath`) emit between segments — `.` between object
|
|
20
|
+
* keys, `[` / `]` around array indices. The disambiguator below treats
|
|
21
|
+
* these as benign structural separators: collapsing them into a hyphen
|
|
22
|
+
* is part of the canonical id form and does NOT signal a collision
|
|
23
|
+
* risk, so no hash suffix is appended for paths like `user.preferences`
|
|
24
|
+
* or `tags[0]`. ASCII whitespace is included for the same reason —
|
|
25
|
+
* label-derived suffixes may carry incidental whitespace.
|
|
26
|
+
*/
|
|
27
|
+
const STRUCTURAL_SEPARATOR_PATTERN = /^[.[\]\s]+$/;
|
|
28
|
+
/**
|
|
18
29
|
* Normalise a structural path into the id segment used after the `sc-`
|
|
19
30
|
* prefix. Whitelist-based: any run of characters outside `[A-Za-z0-9_-]`
|
|
20
31
|
* collapses to a single hyphen, with trailing hyphens stripped.
|
|
@@ -22,21 +33,82 @@ import "./cssClasses.mjs";
|
|
|
22
33
|
* Whitelist (not blacklist) so unexpected characters from free-text sources
|
|
23
34
|
* — `meta.description`, label-derived suffixes, encoded JSON Pointers —
|
|
24
35
|
* cannot leak into ids and break CSS selectors or aria associations.
|
|
36
|
+
*
|
|
37
|
+
* Non-ASCII inputs (e.g. CJK property names like `名前`, accented Latin
|
|
38
|
+
* like `café`, emoji like `🦄`) collapse under the whitelist to a short
|
|
39
|
+
* or empty string and would silently collide on `sc-`. To keep ids
|
|
40
|
+
* deterministic AND unique per input, the normaliser appends a short
|
|
41
|
+
* hash suffix derived from the original string whenever the whitelisted
|
|
42
|
+
* collapse:
|
|
43
|
+
*
|
|
44
|
+
* - produces an empty string, OR
|
|
45
|
+
* - dropped non-structural characters from the input (i.e. anything
|
|
46
|
+
* besides the path joiners `.`, `[`, `]` and ASCII whitespace).
|
|
47
|
+
*
|
|
48
|
+
* Structural separator runs do NOT trigger the disambiguator so
|
|
49
|
+
* canonical paths like `user.preferences` and `tags[0]` keep their
|
|
50
|
+
* historic readable form (`user-preferences`, `tags-0`).
|
|
51
|
+
*
|
|
52
|
+
* The hash is a 32-bit FNV-1a variant rendered in base-36. It is
|
|
53
|
+
* deterministic (same input → same output), short (≤ 7 characters), and
|
|
54
|
+
* non-cryptographic — collision resistance is good enough for DOM ids,
|
|
55
|
+
* and a cryptographic primitive is unnecessary and not universally
|
|
56
|
+
* available (no `crypto` global in every JS runtime that consumes the
|
|
57
|
+
* library).
|
|
58
|
+
*
|
|
59
|
+
* The leading character is guaranteed to be an ASCII letter so the full
|
|
60
|
+
* `sc-<segment>` id is always a valid CSS identifier and `querySelector`
|
|
61
|
+
* target. Empty-collapse inputs receive a synthetic `u` (for "unicode")
|
|
62
|
+
* prefix on the hash so the id never starts with a digit.
|
|
25
63
|
*/
|
|
26
64
|
function normaliseIdSegment(value) {
|
|
27
|
-
|
|
65
|
+
const collapsed = value.replace(/[^A-Za-z0-9_-]+/g, "-").replace(/-+$/g, "");
|
|
66
|
+
if (collapsed.length === 0) return `u${hashSuffix(value)}`;
|
|
67
|
+
if (collapsed !== value && droppedNonStructural(value)) return `${collapsed}-${hashSuffix(value)}`;
|
|
68
|
+
return collapsed;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* True when `value` contains at least one character outside both the
|
|
72
|
+
* id whitelist `[A-Za-z0-9_-]` and the structural separator set
|
|
73
|
+
* (`.`, `[`, `]`, ASCII whitespace). Used by `normaliseIdSegment` to
|
|
74
|
+
* decide whether a non-canonical dropped character (a real Unicode
|
|
75
|
+
* character, a label-derived punctuation, etc.) means the collapse is
|
|
76
|
+
* lossy and disambiguation is required.
|
|
77
|
+
*/
|
|
78
|
+
function droppedNonStructural(value) {
|
|
79
|
+
const nonWhitelisted = value.replace(/[A-Za-z0-9_-]+/g, "");
|
|
80
|
+
if (nonWhitelisted.length === 0) return false;
|
|
81
|
+
return !STRUCTURAL_SEPARATOR_PATTERN.test(nonWhitelisted);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Deterministic 32-bit FNV-1a hash of `value` rendered in base-36. Used
|
|
85
|
+
* solely to disambiguate id segments that would otherwise collide after
|
|
86
|
+
* the whitelisted character collapse; not security-sensitive, so a
|
|
87
|
+
* non-cryptographic hash is sufficient and avoids depending on platform
|
|
88
|
+
* `crypto` availability.
|
|
89
|
+
*/
|
|
90
|
+
function hashSuffix(value) {
|
|
91
|
+
let hash = 2166136261;
|
|
92
|
+
for (let i = 0; i < value.length; i++) {
|
|
93
|
+
hash ^= value.charCodeAt(i);
|
|
94
|
+
hash = Math.imul(hash, 16777619);
|
|
95
|
+
}
|
|
96
|
+
return (hash >>> 0).toString(36);
|
|
28
97
|
}
|
|
29
98
|
/**
|
|
30
|
-
* Build the canonical `sc-`-prefixed DOM id for a structural path.
|
|
31
|
-
*
|
|
99
|
+
* Build the canonical `sc-`-prefixed DOM id for a structural path. Use
|
|
100
|
+
* this as the base id for an input element; derived ids (panel, tab,
|
|
32
101
|
* hint) compose suffixes onto the returned string.
|
|
33
102
|
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
103
|
+
* An empty `path` is permitted — it surfaces as the bare prefix `sc-`
|
|
104
|
+
* so a leaf renderer at the schema root (e.g.
|
|
105
|
+
* `renderToHtml(z.string())`) still emits a usable id without throwing.
|
|
106
|
+
* Container renderers always thread a non-empty path through
|
|
107
|
+
* `renderChild`, so the empty-id case can never produce sibling
|
|
108
|
+
* collisions inside a structured form.
|
|
37
109
|
*/
|
|
38
110
|
function fieldDomId(path) {
|
|
39
|
-
if (path.length === 0)
|
|
111
|
+
if (path.length === 0) return "sc-";
|
|
40
112
|
return `sc-${normaliseIdSegment(path)}`;
|
|
41
113
|
}
|
|
42
114
|
/**
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/core/limits.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { i as MaxRefDepth, n as MAX_REF_DEPTH, r as MAX_RENDER_DEPTH, t as MAX_PATH_ITEM_REF_HOPS } from "../limits-
|
|
1
|
+
import { i as MaxRefDepth, n as MAX_REF_DEPTH, r as MAX_RENDER_DEPTH, t as MAX_PATH_ITEM_REF_HOPS } from "../limits-x4OiyJxh.mjs";
|
|
2
2
|
export { MAX_PATH_ITEM_REF_HOPS, MAX_REF_DEPTH, MAX_RENDER_DEPTH, MaxRefDepth };
|
package/dist/core/limits.mjs
CHANGED
|
@@ -18,6 +18,11 @@ const MAX_REF_DEPTH = 64;
|
|
|
18
18
|
* Maximum number of `$ref` hops permitted when walking a chain of
|
|
19
19
|
* OpenAPI Path Item Object references. Beyond this a
|
|
20
20
|
* `path-item-ref-too-deep` diagnostic is emitted and resolution stops.
|
|
21
|
+
*
|
|
22
|
+
* Also the default `maxHops` for the generic `resolveRefChain` helper
|
|
23
|
+
* in `core/refChain.ts`, so every ref-chain walker — Path Item refs,
|
|
24
|
+
* Parameter / Response refs, Reference Object chains, etc. — shares
|
|
25
|
+
* the same hop cap.
|
|
21
26
|
*/
|
|
22
27
|
const MAX_PATH_ITEM_REF_HOPS = 8;
|
|
23
28
|
//#endregion
|
package/dist/core/merge.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { i as DiagnosticsOptions } from "../diagnostics-
|
|
1
|
+
import { i as DiagnosticsOptions } from "../diagnostics-BTrm3O6J.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/core/merge.d.ts
|
|
4
4
|
/**
|
|
@@ -76,6 +76,17 @@ interface Discriminated {
|
|
|
76
76
|
* uses `kind` while another uses `type`) detection fails and a
|
|
77
77
|
* `discriminator-inconsistent` diagnostic is emitted so callers can
|
|
78
78
|
* see why the union falls back to a generic oneOf.
|
|
79
|
+
*
|
|
80
|
+
* When two or more options share the same discriminator `const` value,
|
|
81
|
+
* the union is still treated as discriminated — the first-match
|
|
82
|
+
* behaviour in `resolveDiscriminatedActive` (in `core/unionMatch.ts`)
|
|
83
|
+
* resolves the active option — but a `discriminator-duplicate`
|
|
84
|
+
* diagnostic is emitted so the unreachable branch is visible to the
|
|
85
|
+
* consumer. Changing the behaviour to fall back to a generic union
|
|
86
|
+
* would be a silent regression for the much commoner case of two
|
|
87
|
+
* intentionally-identical discriminator values appearing in distinct
|
|
88
|
+
* sub-schemas (e.g. an `allOf`-driven hierarchy where the base option
|
|
89
|
+
* duplicates the leaf).
|
|
79
90
|
*/
|
|
80
91
|
declare function detectDiscriminated(options: unknown[], diagnostics?: DiagnosticsOptions, pointer?: string): Discriminated | undefined;
|
|
81
92
|
//#endregion
|