Unreleased
v0.11.2 (2026-11-05)
Bug Fixes and Improvements
Fix 26 format-validation failures exposed by the updated official JSON Schema Test Suite commit 245a45a across Draft 7 and Draft 2020-12. (#21)
- Fix
emailvalidation to accept empty quoted local parts and case-insensitive IPv6 address-literal tags. Reject non-ASCII quoted content, including escaped characters, while preserving Unicode support foridn-email. - Apply non-transitional UTS 46 mapping and NFC normalization before validating
idn-hostnamelabels, supporting fullwidth characters, ignored zero-width spaces, and ACE prefixes produced by mapping. Preserve encoded label/domain length limits, canonical Punycode validation, and domain-wide Bidi checks. - Validate
uri-templateliteral characters and percent-encoded triplets according to RFC 6570, rejecting spaces, control characters, DEL, and malformed percent escapes while preserving permitted Unicode literals. Keep literal segments separate so percent escapes cannot span expressions.
v0.11.1 (2026-11-04)
Bug Fixes and Improvements
Fix compiler and test warnings on Elixir 1.20 and add reproducible Alpine-based testing. (#20)
v0.11.0 (2026-11-04)
Security
Fix validation bypass on regex match-limit exhaustion. (#19)
- Fix regex match-limit exhaustion being treated as a non-match in both supported drafts, preventing
patternPropertiessubschema bypasses andnot/combinator inversions of regex failures. - Report regex engine failures as
:indeterminate_patternerrors and stop validation, preserving the affected string, instance path, and error reason. Coverpattern,propertyNames, and all cached and uncachedpatternProperties/additionalPropertiesmatching paths. Existing execution limits remain unchanged; rewrite excessive-backtracking patterns to avoid rejecting valid data.
Bug Fixes and Improvements
Fix nested numeric equality and streamline uniqueItems validation. (#17)
- Fix
uniqueItemsnumeric equality recursively inside arrays and objects, so nested values such as[1]and[1.0]are recognized as duplicates. Retain exact object-key semantics, hash-collision checks, and original validation inputs. - Replace uniqueness reduction callbacks with early-exit tail recursion, avoiding continuation tuples while retaining numeric-aware scalar hashing. Reuse unchanged branches when normalizing composite hash keys.
Reduce compilation, scope-scanning, validation, and fragment-bundling overhead while preserving resource ownership and URI semantics. (#16)
- Skip empty definition-compilation work when
$defsis absent, avoid generic pointer encoding for plain ASCII definition names, and share identical definition and local-reference maps. Preserve canonical escaping and collisions between escaped and legacy definition keys. - Store Draft 2020-12 scanner registry entries directly, tracking lexical resource contexts only when requested and avoiding intermediate entry wrappers and registry conversions. Preserve discovery order and duplicate-identity precedence.
- Avoid redundant URI-base extraction when reference owners differ or source IDs already match, retaining strict raw-owner and resource-base checks.
- Fast-path compiled references with resolved registry keys, avoiding intermediate lookup tuples and binary-prefix match allocations while preserving fragment-only lookup, resource ownership, dynamic scope, and missing-target fallback.
- Reject non-string
$refvalues during schema compilation with structuredinvalid_keyword_valueerrors, including nested schemas, selected fragments, and compile-time macros. Keep empty-string references valid and make compiled reference keys explicitly binary-only. - Skip URI-base extraction for anonymous (
nil-base) resources during fragment bundling, preserving the distinction between missing and explicit empty bases in bundled output.
Fix resource-local reference ownership, and simplify URI and validation context handling. (#15)
- Isolate eagerly compiled JSON Pointer aliases by resource in both Draft 7 and Draft 2020-12, preventing caller-local aliases from shadowing remote, embedded-resource, or built-in targets. Preserve same-resource cache reuse, selected-fragment pointer roots, escaped definition names, and finalized caches across retrieval and canonical URIs.
- Preserve enclosing pointer roots and resource-owned caches when references enter named-fragment IDs or anchors, including embedded resources and anchors retained from older snapshots sharing a canonical URI.
- Resolve Draft 7 plain-name fragment IDs under anonymous or relative bases without resolving compiled registry keys twice, including loaded fragments and retained resource snapshots. Keep JSON Pointer lookups scoped to the active resource;
$iddoes not define virtual pointer paths. - Preserve inherited vocabulary behavior when
$dynamicRefre-enters an anonymous root, recognizing itsniland""base representations only when raw ownership matches. - Simplify compiled reference metadata: keep registered targets' pointer roots and caches in
rawandlocal_refs, and retain each target's own$dynamicAnchorname indynamic_anchor. - Centralize reference lookup, resource ownership, and context preparation in
JSONSchex.Validator.Reference, removing reference-entry flags fromJSONSchex.Validatorwhile preserving structural and dynamic-scope transitions. - Rename internal scope-scanner entry points from
scan/2andscan_all/3toscan_schema/2andscan_document/3, clarifying schema-tree versus containing-document discovery. Remove the old names without compatibility aliases. - Add
JSONSchex.URIUtil.base/1for fragment-free URI extraction, distinguishing missing (nil) from empty ("") bases. Reuse it across compilation, scope discovery, reference resolution, and bundling. - Rename
JSONSchex.URIUtil.with_fragment/2tojoin_fragment/2to clarify its concatenation-only behavior. Retainwith_fragment/2as a deprecated compatibility alias; joining behavior is unchanged. - Simplify
JSONSchex.URIUtil.split_fragment/1with:binary.split/3, preserving first-delimiter splitting and empty-fragment normalization.
Add Draft 7 support, fix pre-existing issues that affect both supported drafts, and improve shared infrastructure and dependencies. (#14)
Draft 7 support and correctness
These changes implement Draft 7 behavior. Fixes for pre-existing shared defects are listed separately below.
- Support tuple-form
items,additionalItems, and Draft 7$refsibling semantics alongside Draft 2020-12. - Embed the canonical Draft 7 meta-schema and cache its compiled reference registry by format/content assertion options. Both canonical HTTP URI forms, with and without a trailing
#, share the appropriate cache variant and resolve without a loader or runtime file access. - Make Draft 7 scope discovery ignore
$refsiblings and newer-draft annotations, skip eager$defscompilation, and register resources under tupleadditionalItems. Preserve explicit JSON Pointer references into annotation content. - Discover nested
$idresources in explicitly referenced pointer targets, including targets under ignored content or in other registered resources, without activating unrelated siblings or loading external schemas. Follow transitive pointers, retry lookups after resource discovery or promotion, preserve fragment-ID pointer roots even with relative retrieval bases, and terminate discovery cycles. - Register ancestor resources crossed by explicit pointer and selected-entry routes so targets can refer back to them. Keep these metadata-only registrations lower priority than ordinary discovery, including through transitive references and regardless of pointer order.
- Compile selected fragments and eager pointer targets against their inherited ancestor
$idbase, applying each resource ID once. Retain the containing document and retrieval base for discovery, and use the owning resource as the JSON Pointer root without promoting fragment-only IDs or ignored$refsibling IDs to resource roots. - Replace inherited URI fragments in references beneath Draft 7 named-fragment IDs, so
#selects the enclosing resource root rather than an ancestor's named subschema. - Ensure an ignored Draft 7
contentSchemadoes not suppress enabledcontentEncodingandcontentMediaTypeassertions. - Refactor Draft 7 scope scanning to use named state and owner maps with focused traversal and merging helpers. Preserve fallback-resource precedence, reference replay, owner-change detection, and cycle termination.
- Run an independent official Draft 7 suite and add compatibility, reference, cache, and compile-time embedding regressions.
Shared fixes for Draft 7 and Draft 2020-12
These fixes apply to both drafts and address defects already present in the Draft 2020-12 implementation on main. They are not regressions introduced by Draft 7 support.
- Honor
:base_uriduring schema scope discovery, resolving relative$idresources and Draft 2020-12 anchors against the supplied retrieval base instead of registering unqualified identities. - Preserve ancestor
$idscopes and the owning raw resource during JIT pointer compilation without reapplying the resource root's ID. Subsequent local and absolute references resolve against that resource rather than the selected leaf, fixing reference resolution within embedded resources. - Resolve empty self-references against the current raw resource without loading an unregistered retrieval URI.
- Resolve absolute JSON Pointer references to the current URN resource locally instead of passing the full URN to JSON Pointer lookup.
- Assert standalone
contentEncodingandcontentMediaTypewhencontent_assertion: true, even withoutcontentSchema. Content handling remains annotation-only by default.
Shared infrastructure and maintenance
These changes support both drafts; they are infrastructure and maintenance updates rather than fixes for pre-existing defects on main.
- Select the draft from a recognized root
$schemaor the string-valued:draftoption ("draft7"or"draft2020_12"), retaining Draft 2020-12 as the fallback. Return structured errors for conflicting declarations or invalid options; compile-time schema macros raiseCompileError. Fragment compilation uses the containing document's root declaration. - Dispatch scope discovery through draft-specific scanners behind the shared scope-scanner interface.
- Upgrade
ex_json_pointerto~> 0.9and pass decoded reference tokens directly to ancestor traversal. - Update the optional
decimalrequirement to~> 3.2(previously~> 1.0 or ~> 2.0 or ~> 3.0). - Expand shared regression coverage and update the README, guides, and changelog. Both official draft suites retain the
optional/cross-draftexclusion; complete cross-draft support is not claimed.
v0.10.0 (2026-09-14)
Bug Fixes and Improvements
Add a Git-baseline JSONSchex before/after benchmark suite covering broad validation cases and focused bundle, compile, scan, and validation workloads. (#13)
Optimize two-rule validation dispatch by reserving the pattern-match-cache path for exact sibling
patternPropertiesandadditionalPropertiespairs; other two-rule schemas retain their direct fast path. (#12)Reduce repeated validation work and allocations. (#11)
- Count Unicode code points for
minLengthandmaxLengthwithout allocating a charlist for inputs larger than 256 bytes, while retaining the standard conversion for shorter inputs. Malformed UTF-8 now produces a validation error witherror_detail: "invalid_utf8"instead of raisingUnicodeConversionError. - Compile each
patternPropertiesregex once when the same schema also usesadditionalProperties, with a bounded per-schema cache that preserves vocabulary gates, error behavior, and validation semantics. - Reuse runtime pattern-match classification between sibling
patternPropertiesandadditionalPropertiesrules within one validation invocation, reducing repeated regex matching for wide objects while preserving rule order, annotations, and diagnostics. - Adaptively merge evaluated keys from parent-dominated
anyOfbranches with balancedMapSetunions, avoiding repeated conversion of shared incoming evaluated keys while preserving full branch traversal, evaluated-key inputs, diagnostics, and legacy list-key behavior. - Avoid rebuilding already-flat validation error lists at the public validation boundary, and fuse nested error flattening with legacy error formatting while preserving diagnostic order, values, and internal error grouping.
- Remove redundant input-key presence checks when validating
required, while preserving declaration order, duplicate entries, non-object behavior, and diagnostic shape. - Avoid rescanning built-in Draft 2020-12 resources after compilation, and reduce scope-scanner traversal intermediates while preserving resource identities, anchor targets, and traversal precedence.
- Count Unicode code points for
Reuse already-compiled schema nodes when their compilation context matches, reducing repeated compilation while preserving resource scope, rule order, and context-sensitive behavior. (#10)
Improve fragment-bundling performance by avoiding repeated descendant metadata indexing, accumulating fallback-anchor candidates without repeated list scans, and skipping deep reference-rewrite passes when external-reference aliases are identities. (#9)
v0.9.3 (2026-09-07)
Bug Fixes and Improvements
- Explicitly use
ex_json_pointer ~> 0.8, which is a performance-improved version.
v0.9.2 (2026-08-07)
Bug Fixes and Improvements
- Fix arbitrary-precision
multipleOfvalidation by checking Decimal coefficients and exponents exactly, avoiding context-dependent rounding, quotient-size errors, and validation crashes for large integers
v0.9.1 (2026-08-06)
Bug Fixes and Improvements
- Update Draft 2020-12 optional format validation to match the current official test suite (commit cc73f5f):
- Validate
regexstrings against ECMA-262 syntax rather than PCRE extensions, including support for empty character classes and variable-width lookbehind - Require complete input for
duration,uuid, andrelative-json-pointerformats; require RFC 3339 numeric timezone offsets to include minutes - Enforce RFC 6570 URI-template prefix modifiers as non-zero values with at most four digits
- Validate
v0.9.0 (2026-07-23)
Bug Fixes and Improvements
- Update
JSONSchex.bundle_fragment/2to bundle only the schema graph reachable from the selected entrypoint, without loading unrelated refs from other components, examples, or extension data. Local pointers, anchors, nested$idresources, recursive graphs, and loader-provided base URIs remain supported; caller-owned$defsentries are preserved with collision-safe internal keys, while invalid$defsand ambiguous anchors return structuredinvalid_defsorambiguous_anchorerrors - Change
JSONSchex.Ref.resolve_selected/2so an unselected$refmap is preserved but no longer terminates traversal: its sibling values are walked,:selectis invoked for descendant$refnodes that earlier releases skipped, and every descendant ref left unselected is rebased through loader-provided:base_uriand nested$idboundaries without loading its target - Some Dialyzer compile warnings fixed
- Improved
ipformat validation - Update the official Draft 2020-12 optional format-suite coverage and align format validation:
- Adapt the
idn-emaillone UTF-16 surrogate case for Elixir JSON decoders, reject ill-formed UTF-8 input, and accept valid non-NFC domain labels by normalizing only the domain before IDNA hostname validation - Reject signed years in the RFC 3339
dateformat, which requires exactly four unsigned year digits - Strengthen
idn-hostnamevalidation: reject malformed or non-canonical A-labels, encoded hostnames longer than 253 characters, and Bidi domains with invalid label directionality; Unicode and Punycode forms are validated equivalently
- Adapt the
v0.8.1 (2026-06-15)
Bug Fixes and Improvements
- Preserve the loaded resource base for unselected nested
$refs inside external targets resolved byJSONSchex.Ref.resolve_selected/2, so laterJSONSchex.bundle_fragment/2andJSONSchex.compile_fragment/2calls resolve those refs against their original document
v0.8.0 (2026-06-07)
Breaking Changes
- Replace the separate
:entry_pointerand:entry_refoptions forJSONSchex.compile_fragment/2,JSONSchex.bundle_fragment/2, andJSONSchex.Schema.compile_fragment!/2with a single:entryoption that accepts either a JSON Pointer or URI reference
v0.7.0 (2026-05-23)
Bug Fixes and Improvements
- Add
JSONSchex.compile_fragment/2andJSONSchex.Schema.compile_fragment!/2for compiling JSON Schema fragments while preserving the containing document as the local reference context, useful for OpenAPI 3.1 schemas under paths and components. Fragment entrypoints support exactly one of:entry_pointeror:entry_ref, with:entry_refproviding a base URI/path when:base_uriis omitted - Add
JSONSchex.bundle_fragment/2for producing standalone raw schemas from document fragments, including reachable external resources mounted under$defs - Add
JSONSchex.Ref.resolve_selected/2for selector-driven$refresolution in JSON-like documents, allowing callers such as OpenAPI tooling to choose which$refnodes are replaced while preserving unselected refs
Breaking Changes
- Rename the remote/reference loading option from
:external_loaderto:loader
v0.6.0 (2026-05-09)
Bug Fixes and Improvements
- Add first-class support for compiling static JSON Schema literals during module compilation via
JSONSchex.Schema.compile!/2and the~Xsigil inJSONSchex.Sigil - Refactor validation and compiled rule execution to support static compile-time embedding by making rules data-driven and dispatching them through
JSONSchex.Validator.Rules - Precompute legacy
dependenciesexecution modes during compilation and simplify runtime rule matching - Prune several compile-time no-op keyword rules such as empty
required,properties,patternProperties,dependentRequired,dependentSchemas, andprefixItems - Relax decimal dependency requirement
v0.5.0 (2026-04-23)
Bug Fixes and Improvements
- Embed the Draft 2020-12 built-in meta-schema family directly in code and cache compiled built-in defs for
$refand$dynamicRefresolution - Refactor built-in Draft 2020-12 support into draft-specific modules:
JSONSchex.Draft202012.Schemas,JSONSchex.Draft202012.Vocabulary, andJSONSchex.Draft202012.Dialect - Simplify and de-duplicate reference resolution logic, including URI fragment handling and loaded-schema validation flow
- Fix built-in meta-schema validation so schemas can be validated against the canonical Draft 2020-12 meta-schema without an external loader
- Update official test suite, and adapt to pass the official Draft 2020-12 optional format cases for
duration,time, anduri:- Tighten
durationformat validation to match the RFC 3339 Appendix A grammar used by the official Draft 2020-12 optional format suite - Accept RFC 3339
timevalues with unknown local offset (-00:00) - Tighten
urianduri-referenceformat validation to reject invalid percent-encoding triplets
- Tighten
v0.4.0 (2026-04-05)
Bug Fixes and Improvements
- Fixed an issue where $ref could cause an infinite loop during validation
- Refactor compile-time and validation-time failures to use the unified
JSONSchex.Types.Errormodel with structuredErrorContext - Improve error formatting so invalid keyword and compile errors produce clearer, more contextual messages
- Treat the canonical Draft 2020-12 meta-schema as a built-in dialect without requiring a loader, while still honoring explicit
$vocabularydeclarations - Split vocabulary handling between supported vocabularies and the built-in Draft 2020-12 default active vocabulary set
- Optimize local
$refcompilation by batching JSON Pointer resolution for explicit local fragment references - Improve scope scanning so
$id, anchors, and explicit local fragment refs are registered more consistently - Consolidate
timeformat validation into the date-time format implementation
v0.3.0(2026-02-21)
Bug Fixes and Improvements
- Refactor the error context to make it more consistent
v0.2.1 (2026-02-20)
Bug Fixes and Improvements
- Enhance some keywords validation.
v0.2.0 (2026-02-20)
Bug Fixes and Improvements
- Enhance some keywords checking in compile.
v0.1.0 (2026-02-16)
- Initial Release