Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

### Unreleased

* Add opt-in `unicode_subset` and `on_invalid_char` options for RFC 9839 Unicode repertoires in parsing and generation, including Coder and ResumableParser.
* JRuby: parser errors now include the position (`line`, `column` and the message suffix) as well as `json_path`, matching the C extension.

### 2026-09-09 (3.0.2)
Expand Down
29 changes: 29 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,35 @@ JSON.generate(data)
You can also use the `pretty_generate` method (which formats the output more
verbosely and nicely).

## Standards compliance

The optional `unicode_subset` setting restricts object keys and string values to
one of the repertoires in [RFC 9839](https://www.rfc-editor.org/rfc/rfc9839.html):

* `:scalars` requires well-formed Unicode, excluding surrogates.
* `:xml_characters` also excludes legacy C0 controls and U+FFFE/U+FFFF.
* `:assignables` also excludes DEL, C1 controls, and all noncharacters.

Unassigned and private-use codepoints remain allowed. The default, `nil`, keeps
the existing behavior. These options work with parsing, generation, `JSON::Coder`,
and `JSON::ResumableParser` (where available).

```ruby
JSON.parse('"\u0089"', unicode_subset: :assignables) # raises JSON::ParserError
JSON.generate("\u0089", unicode_subset: :assignables) # raises JSON::GeneratorError
JSON.parse('"\u0089"', unicode_subset: :assignables, on_invalid_char: :replace) # => "�"
```

`on_invalid_char` defaults to `:raise`. With `:replace`, forbidden codepoints and
each maximal subpart of malformed UTF-8 become U+FFFD. With no subset selected,
replacement only relaxes parsing of unpaired `\uXXXX` surrogate escapes.
Escapes cannot bypass a subset restriction; `allow_control_characters` only
relaxes JSON syntax. Keep duplicate-key detection enabled when replacing
characters, since different keys can become equal after replacement.

Replacement cannot be combined with `rfc8785: true`. Raw `JSON::Fragment` contents
and custom `to_json` output remain the caller's responsibility.

## Casting non native types

JSON documents can only support Hashes, Arrays, Strings, Integers and Floats.
Expand Down
2 changes: 2 additions & 0 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ if defined?(RUBY_ENGINE) and RUBY_ENGINE == 'jruby'
parser_classes = FileList[
"json/ext/ByteList*.class",
"json/ext/OptionsReader*.class",
"json/ext/UnicodeSubset*.class",
"json/ext/Parser*.class",
"json/ext/Ryu*.class",
"json/ext/RuntimeInfo*.class",
Expand All @@ -187,6 +188,7 @@ if defined?(RUBY_ENGINE) and RUBY_ENGINE == 'jruby'
generator_classes = FileList[
"json/ext/*ByteList*.class",
"json/ext/OptionsReader*.class",
"json/ext/UnicodeSubset*.class",
"json/ext/EscapeScanner*.class",
"json/ext/Generator*.class",
"json/ext/RuntimeInfo*.class",
Expand Down
Loading
Loading