Changes for version 0.03 - 2026-06-02
- Bug Fixes
- Handle address not being in parts
- Fix mkdir operator-precedence bug that silently ignored directory creation failures
- Fix cache read: open failure now warns gracefully instead of dereferencing undef filehandle
- Fix cache write: open failure now warns instead of crashing on undef filehandle print
- Fix TOCTOU race between file existence check and open by opening directly
- Add stale-cache fallback when network fetch of Schema.org vocabulary fails
- Fix exit code being overwritten by each validation error; first error now wins
- Fix enum validation false-positives for array/hash-valued JSON-LD properties
- Fix addressCountry static enum to use ISO 3166-1 alpha-2 codes (was mixed underscore strings)
- Fix Boolean property validation to accept JSON::PP::Boolean objects (decoded true/false)
- Fix country code validation to accept ISO 3166-1 alpha-3 codes (e.g. USA) as well as alpha-2
- Fix startDate property_validations key casing (was lowercase 'startdate', never matched JSON-LD)
- Fix SARIF uri field being undef when reading from STDIN; now defaults to '-'
- Fix Integer validation incorrectly accepting decimal numbers (was sharing Number regex)
- Fix die list-form in bin/extract-event losing the URL from the error message
- Fix bin/extract-event2 die list-form losing the URL from the error message
- Fix %config declared as lexical (my); changed to our so callers can override ua_timeout, cache_file, cache_duration, vocab_url at runtime
- Fix default cache_file location: was CWD-relative; now uses $ENV{CACHEDIR} if set, otherwise File::Spec->tmpdir() (e.g. /tmp), never the process CWD
- Fix crash when Schema.org vocabulary JSON is a non-object (e.g. a bare array); load_dynamic_vocabulary now carps and returns {} instead of dying "Not a HASH reference"
- Fix POD for is_valid_datetime: PURPOSE section incorrectly stated timezone offsets and calendar sanity were not validated; both are enforced via DateTime::Format::ISO8601
- Fix POD for load_dynamic_vocabulary: ARGUMENTS spec had optional=>1 for the required string parameter; corrected to optional=>0
- Fix POD NOTES for load_dynamic_vocabulary: stale note claimed bin/validate-schema had its own independent copy; it now imports from the module
- Enhancements
- Replace is_valid_datetime regex with DateTime::Format::ISO8601; now rejects invalid calendar values (e.g. month 99) and accepts timezone designators (Z, +HH:MM)
- Replace email validation regex in validate_property_format with Email::Valid
- Replace DateTime type-branch regex in validate_property_format with is_valid_iso8601, consistent with the adjacent Date branch
- Replace Number validation regex with Scalar::Util::looks_like_number (was imported but unused); Integer now validated separately with a strict /^\d+$/ pattern
- Replace JSON-LD extraction regex in bin/extract-event with Mojo::DOM CSS selector, handling CDATA sections and unusual attribute ordering
- Replace HTML::TreeBuilder and JSON-LD extraction regex in bin/extract-event2 with Mojo::DOM throughout; removes the HTML::TreeBuilder dependency
- Hoist validate-schema exit-code map to file-level Readonly::Hash; was rebuilt on every push_validation call
- Add property-name Readonly constants to validate-schema; removes magic strings from the static schema rules table
- Import is_valid_datetime and load_dynamic_vocabulary from Schema::Validator module into bin/validate-schema; removes ~160 lines of duplicated code
- Add _organizer_field helper to bin/extract-event; removes duplicated organizer array/object extraction logic
- Switch bin/extract-event and bin/extract-event2 from JSON to JSON::MaybeXS
- Add Email::Valid, Mojolicious, and Readonly to cpanfile prerequisites
- Added a test dashboard
- Tests
- Add t/function.t: white-box subtests for every function including internal helpers (_slurp_file, _spit_file, _fetch_url, _extract_label, _parse_graph) using Test::Mockingbird; 41 subtests
- Add t/unit.t: black-box unit tests per POD API documentation; 33 subtests
- Add t/integration.t: end-to-end tests across both public functions with Test::Mockingbird::Spy verifying external call arguments; 29 subtests
- Add t/edge_cases.t: destructive, pathological, boundary, and security subtests including typeglob inputs, circular references, and upstream failure mocks; 49 subtests
- Add t/extended_tests.t: coverage-gap targeted tests achieving >=97% statement coverage; documents two genuinely unreachable paths; 27 subtests
- Add t/mutant_killers.t: mutant-killing tests for all 21 stubs in the generated xt/mutant_*.t stub; kills BOOL_NEGATE, RETURN_UNDEF, COND_INV, NUM_BOUNDARY mutations across lines 297-711 using utime-based cache-freshness boundary tests; 27 subtests
- Total test suite: 228 subtests across 10 files, all passing under prove -lt
Documentation
Modules
Tools for validating and loading Schema.org vocabulary definitions