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