Revision history for Perl module JSON::Schema::Validate
v0.6.1 2025-11-26T19:04:00+0900
[Fixes: $ref Resolution]
- Corrected handling of internal JSON Pointer fragments in $ref during interpreted
(Perl) validation. The engine now resolves fragments such as
"#/definitions/address" and "#/$defs/address" using the same resolution logic as
the JavaScript compiler (via _jsv_resolve_internal_ref), ensuring consistent
behaviour across interpreted and compiled modes.
- Fixed aliasing rules between "definitions" and "$defs" in accordance with the
2020-12 specification: both locations are now recognised bidirectionally when
resolving $ref.
- Improved error reporting for unresolved internal references:
* keyword => '$ref'
* schema_pointer => pointer to the schema node containing
the failing $ref
* message => "unresolved JSON Pointer fragment in $ref …"
ensuring correct failure location and fully deterministic errors.
[Interpreted Validator Improvements]
- $ref resolution now attempts anchor lookup, id_index lookup, JSON Pointer lookup,
and definitions/$defs alias mapping before falling back to the external resolver
hook.
- Behaviour now matches compile_js(): valid internal references resolve immediately;
unresolved references produce a clean '$ref' error rather than misrouting to a
parent keyword.
[Tests]
- Added comprehensive regression tests under t/083_defs_refs.t:
* Resolution of "#/definitions/…" and "#/$defs/…" under both interpreted and
compiled modes.
* Aliasing behaviour where "#/definitions/…" resolves to entries stored under
"$defs", and vice-versa.
* Correct handling of missing references: detection of unresolved fragments,
correct keyword ('$ref'), correct error message, and correct schema_pointer.
These tests cover both success and failure paths exhaustively.
[Internal]
- Refactored _apply_ref() to unify logic between interpreted and compiled validators
and eliminate discrepancies present in earlier releases.
v0.6.0 2025-11-25T19:17:41+0900
[New Features]
- Added compile_js() to generate a standalone JavaScript validator from the
current schema. The generated code exposes a single global function:
validate(inst) -> [ { path, keyword, message, schema_pointer }, ... ]
using the same error structure as the Perl engine.
- compile_js() supports an 'ecma' option:
ecma => "auto" # default; cautious feature detection
ecma => 2018 # assume ES2018+ (Unicode property escapes, /u, etc.)
allowing callers to tune how aggressively Unicode regexp features are used
in the generated JavaScript.
[JavaScript Codegen]
- Implemented a conservative Perl-regexp to JavaScript converter for
'pattern' keywords:
* \x{...} -> \uHHHH / \u{HHHHH}
* \p{Katakana}, \p{Hiragana}, \p{Han}, etc. -> \p{scx=...}
with proper escaping for use inside new RegExp("...","u").
Patterns that cannot be compiled by the browser are safely skipped on the
client and remain enforced by the Perl validator.
- JavaScript validator now covers:
type, const (primitive), enum,
minLength / maxLength / pattern,
minimum / maximum / exclusiveMinimum / exclusiveMaximum,
minItems / maxItems / items (single-schema form),
contains / minContains / maxContains,
properties / required,
allOf / anyOf / oneOf / not,
if / then / else,
and the non-core 'uniqueKeys' applicator when enabled in Perl.
Negative "not + required" patterns are deliberately skipped client-side and
enforced server-side only, to avoid surprising UX.
[Behaviour Changes]
- For generated JavaScript only: when numeric bound keywords are present
(minimum/maximum/exclusiveMinimum/exclusiveMaximum), numeric-looking
strings such as "10" or "3.14" are coerced to numbers before applying
the bounds. Non-numeric values:
* raise a 'type' error ("expected number but found ...") when no
explicit 'type' is declared, or
* are checked by the schema's 'type' keyword when present.
This provides friendlier form validation in browsers while the Perl
engine remains strictly JSON-typed.
- Ensured error locations and schema pointers reported by the generated
JavaScript match the Perl engine, so server-side and client-side logs
can be correlated easily.
[Documentation & Tests]
- Expanded POD to document compile_js(), its 'ecma' option, the JavaScript
error format, and typical integration in web forms.
v0.5.1 2025-11-20T16:07:53+0900
- Fixed _k_combinator to avoid leaking errors from anyOf/oneOf branches
into the main validation context; only the selected branch now contributes
errors and annotations.
- Fixed _k_if_then_else so that the "if" subschema is always evaluated in a
shadow context. Keywords such as "required" inside "if" no longer produce
spurious failures when the condition is not satisfied; only "then"/"else"
affect the outcome.
- Improved error reporting to include both the schema pointer and the
instance path, along with required vs present properties, which makes
debugging nested combinators (anyOf/oneOf/if/then/not) much easier.
- Added regression tests covering if/then with conditional "required", and
a oneOf-based "shares" schema combining simple totals and share classes,
including edge cases around "golden" and "no voting right" shares.
v0.5.0 2025-11-19T18:15:12+0900
[Bug Fixes]
- Corrected bad unit tests (thanks Slaven Rezić, GitLab #3).
[New Features]
- Extensions: Added opt-in support for non-core applicators.
* uniqueKeys: Enforce uniqueness of property values (or tuples) across array items.
Enable via ->extensions(1) or ->unique_keys(1). Off by default.
Example: "uniqueKeys": [ ["id"], ["email"] ]
Fully integrated into both interpreter and compiled fast-path.
- API: New methods extensions(), unique_keys(), is_unique_keys_enabled().
- Tests: comprehensive t/081_unique-keys.t covering single, composite, disabled,
and mixed-type cases.
v0.4.1 2025-11-18T14:21:35+0900
[Bug Fixes]
- Corrected logic in register_builtin_formats() when helper modules such as
DateTime::Format::ISO8601 or Net::IDN::Encode are missing, ensuring
date-time and email / IDN-email formats are validated consistently
(thanks Slaven Rezić, GitLab #2).
- Dropped Regexp::Common as a dependency; the email format now uses a
precomputed RFC 5322-style regex, avoiding a runtime dependency.
v0.4.0 2025-11-16T15:50:29+0900
- Added optional pruning support to JSON::Schema::Validate, as it is often required
by REST APIs:
* New constructor option 'prune_unknown' to remove unknown object
properties from instances before validation, based on the schema’s
properties, patternProperties, additionalProperties and allOf keywords.
* New method 'prune_instance' returning a pruned copy of the given
instance without modifying the original data structure.
v0.3.0 2025-11-11T09:20:18+0900
[Error Object Improvements]
- Error reporting overhaul:
* Error objects (JSON::Schema::Validate::Error) now consistently carry: message,
path (instance JSON Pointer), keyword (if known), and schema_pointer
(JSON Pointer to the keyword that failed).
* Stringification shows "schema_pointer → path: message" when a schema pointer
is available; otherwise "path: message".
* More precise messages across keywords (type, const, enum, string
length/pattern, numeric bounds, contains/minContains/ maxContains,
additionalProperties, unevaluated*, dependent*, oneOf/anyOf/allOf/not, content*).
* Resolver failures, unresolved $ref/$dynamicRef, and invalid JSON Pointer
fragments now produce explicit, actionable messages (with keyword set to
'$ref' where applicable).
[CLI]
- Introduced jsonvalidate command-line tool (distribution: App::jsonvalidate)
supporting:
--schema / --instance / --json / --jsonl / --compile / --trace / --register-formats /
--content-checks / --ignore-unknown-required-vocab / --max-errors / --normalize /
--schema-base
- JSON output mode now includes structured errors:
{ path, message, keyword, schema_pointer }
[Documentation]
- Expanded POD for JSON::Schema::Validate::Error, including constructor,
getters/setters, as_string(), as_hash(), and behaviour of overloads.
v0.2.0 2025-11-10T15:30:12+0900
[Core Implementation]
- Full support for JSON Schema Draft 2020-12, including:
* $id / $anchor / $ref with external & fragment resolution,
* $dynamicAnchor / $dynamicRef with correct dynamic scope lookup.
- Recursion safety implemented via (schema_pointer, instance_address) pairs.
- Comprehensive keyword coverage: type (including unions with inline schemas),
const, enum, multipleOf (float-tolerant), numeric bounds, length and pattern,
prefixItems/items, contains(min/max), uniqueItems, unevaluatedItems,
properties / patternProperties / additionalProperties, propertyNames,
required / dependentRequired / dependentSchemas, unevaluatedProperties,
allOf / anyOf / oneOf / not, and if/then/else.
- Unevaluated* keyword handling uses annotation tracking on evaluated nodes
(props/items maps), matching spec semantics.
[New Features]
- Optional ahead-of-time compilation:
* Enables fast-path validation via closures per schema node.
* Use ->compile() or constructor 'compile => 1'.
* Indexes anchors / dynamic anchors for constant-time lookup.
- Content assertions (RFC 8927):
* Enable via ->content_checks() or constructor 'content_assert => 1'.
* Supports contentEncoding (built-in base64), contentMediaType,
pluggable media decoders, and contentSchema validation.
* Ships with 'application/json' decoder/validator.
- Built-in format validators:
* Activate via ->register_builtin_formats().
* Provides validators for date/time/duration (ISO8601), email/idn-email,
hostname/idn-hostname, IPv4/IPv6, URI/IRI/URI-reference, UUID,
JSON Pointer / Relative JSON Pointer, and regex.
* Custom format handlers via ->register_format() or constructor 'format => {}'.
- Tracing and introspection:
* Enable via ->trace().
* Limit / sample with ->trace_limit() and ->trace_sample().
* Retrieve via ->get_trace() (returns a copy).
- Vocabulary enforcement:
* Honors $vocabulary and required entries.
* Unknown vocabularies may be ignored via ->ignore_unknown_required_vocab().
[API Additions]
- Constructor options:
compile, content_assert, format (hash reference of callbacks),
ignore_unknown_required_vocab, max_errors, normalize_instance,
trace, trace_limit, trace_sample, vocab_support (hash reference).
- Methods:
compile(), content_checks(), enable_content_checks(),
ignore_unknown_required_vocab(),
register_content_decoder(), register_format(),
register_media_validator(), set_resolver(), set_vocabulary_support(),
trace(), trace_limit(), trace_sample().
Accessors: is_* variants and get_trace_limit().
- Error handling:
->error() returns the first JSON::Schema::Validate::Error object
(stringifies to '"path: message"').
->errors() returns an array reference (up to max_errors).
[Behavioral Improvements]
- Instance normalisation (enabled by default): round-trips values to enforce
strict JSON typing distinct from Perl dual values. Can be disabled via
'normalize_instance => 0'.
[Bug Fixes & Polish]
- Added missing dependency declarations (thanks Slaven Rezić, GitLab #1).
- Numeric strictness now based on B::FLAGS (IOK/NOK) for correct JSON semantics.
- UTF-8-aware string lengths via codepoint iteration (not bytes).
- All mutator methods return $self for chained configuration.
[Documentation & Tests]
- Expanded POD: constructor options, method semantics, formats, normalisation,
vocabulary behaviour, recursion notes, unevaluated* examples.
- Test suite now covers: dynamic anchors, external refs, combinators,
unevaluated*, content/media assertions, compile vs interpretive modes,
trace output, vocabulary validation, and structured errors.
v0.1.0 2025-11-07T11:59:21+0900
- Initial version