Sitelet https://github.com/jsonrainbow/json-schema/pull/962
Skip to content

Validate iri and iri-reference formats according to RFC 3987 - #962

Merged
DannyvdSluijs merged 2 commits into
mainfrom
feature/iri-format
Sep 22, 2026
Merged

DannyvdSluijs merged 2 commits into
mainfrom
feature/iri-format

Conversation

@DannyvdSluijs

Copy link
Copy Markdown
Collaborator

Summary

iri and iri-reference had no case in the Draft07 / Draft2019 FormatConstraint switch, so they fell through to default and every string was accepted. The optional test suite cases were partly skipped; the percent-encoding cases added upstream in json-schema-org/JSON-Schema-Test-Suite#1184 were not, which accounts for 6 of the current CI failures.

This adds validateIri() (kept per draft) derived from the RFC 3987 §2.2 ABNF:

  • iri = scheme ":" ihier-part [ "?" iquery ] [ "#" ifragment ]; iri-reference additionally accepts irelative-ref (no : in the first segment of a scheme-less relative path).
  • iunreserved includes ucschar; iprivate is only allowed in the query; % must be followed by two hex digits.
  • Bracketed IP literals are checked with filter_var(..., FILTER_FLAG_IPV6) (rejects e.g. ::ffff:192.168.0.01).
  • Anchored with \z, so a trailing new line is rejected ($ would accept it).
  • Character runs are matched possessively: a naïve per-character alternation hits JIT stack limit exhausted at ~8k characters and reports valid values as invalid; this version handles >1M characters.
  • BMP and supplementary ranges live in separate character classes to avoid the PCRE2 10.46 issue described in Fix uri-template rejecting non-Latin literals on PCRE2 10.46 #961.

Errors reuse ConstraintError::FORMAT_url() (iri) and FORMAT_URL_REF() (iri-reference), mirroring uri / uri-reference.

The iri and iri-reference entries are removed from the skip list in JsonSchemaTestSuiteTest, and regression cases (non-Latin characters, trailing new line, lone %, long path) are added to the Draft07 and Draft2019 FormatConstraintTest.

Test plan

  • ./bin/run-test-case {draft7,draft2019-09}/optional/format/iri.json "validation of IRIs" → 26 passed, 0 failed
  • ./bin/run-test-case {draft7,draft2019-09}/optional/format/iri-reference.json "validation of IRI References" → 21 passed, 0 failed
  • Test suite data (draft7, 2019-09, 2020-12) plus BMP / supplementary / private-use samples checked on PCRE 8.41 (PHP 7.2), 10.44 (PHP 8.4) and 10.46
  • composer phpstan → no errors
  • composer test → failures down from 24 to 18; the remaining ones are pre-existing upstream additions for uri-reference (percent-encoding) and idn-email

🤖 Generated with Claude Code

The iri and iri-reference formats had no validation in the Draft07 and
Draft2019 format constraints, so every string was accepted. Add a
validator derived from the RFC 3987 section 2.2 ABNF, checking IPv6
literals with filter_var and anchoring with \z to reject a trailing new
line. Character runs are matched possessively to stay within the PCRE
JIT stack limits for long values, and BMP and supplementary ranges live
in separate classes to avoid a PCRE2 10.46 matching bug.

Remove the now passing iri and iri-reference cases from the test suite
skip list.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

The validator rejects RFC-valid IPvFuture host literals, and the URI-template PHPDocs are misplaced.

Get a fresh assessment by requesting another Copilot review.

Review effort: Balanced
Findings: 2 Low severity

Open (2)
What changed in this PR

Adds RFC 3987 validation for iri and iri-reference formats in Draft07 and Draft2019.

Changes:

  • Implements IRI parsing and percent-encoding validation.
  • Adds Unicode, newline, relative-reference, and performance regression tests.
  • Enables corresponding JSON Schema Test Suite cases.
File Description
src/​JsonSchema/​Constraints/​Drafts/​Draft07/​FormatConstraint.php Adds Draft07 IRI validation.
src/​JsonSchema/​Constraints/​Drafts/​Draft2019/​FormatConstraint.php Adds Draft2019 IRI validation.
tests/​Constraints/​Draft07/​FormatConstraintTest.php Adds Draft07 regression coverage.
tests/​Constraints/​Draft2019/​FormatConstraintTest.php Adds Draft2019 regression coverage.
tests/​JsonSchemaTestSuiteTest.php Enables IRI test-suite cases.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment thread src/JsonSchema/Constraints/Drafts/Draft07/FormatConstraint.php
Comment thread src/JsonSchema/Constraints/Drafts/Draft2019/FormatConstraint.php
Accept IPvFuture host literals as defined in the RFC 3986 / 3987 ABNF,
and move the uri-template docblock back above validateUriTemplate() so
it is no longer orphaned by the validateIri() docblock.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@DannyvdSluijs
DannyvdSluijs merged commit 1857270 into main Sep 22, 2026
5 of 18 checks passed
@DannyvdSluijs
DannyvdSluijs deleted the feature/iri-format branch September 22, 2026 18:16
github-actions Bot added a commit that referenced this pull request Sep 22, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants