json-repair 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b4892b62960d0c4d27976577c506585ea8df11bfbf14dc1a9b40952947ad1f20
4
- data.tar.gz: fe26e3da464e5356bd33021e5b08a7a1f1ad938e125f0ef384777ff64b13f813
3
+ metadata.gz: fdf2958528b936eba0faf6c724a20d10a3a3e0b95329bc1866740c99432f6fe3
4
+ data.tar.gz: 33fa97d2c7689ea594723e5d0d412646cf57a2ebdbf79f3b62947d4928963f32
5
5
  SHA512:
6
- metadata.gz: 4cf46eae9e05e718c978e7a503578bd867bacce1b71565764ec88af8b762f498ceceada6ce37d73663e6bcff56b85013746c7a82e84eda6eb55ed57e3535fe0d
7
- data.tar.gz: f2fc802dd1bfbd26bb04f34ca2902189d11537d4bbbebc131d14ef7672bcd9f2dd01bcc2157182ba6801eea0f92693883086197013add4f86f69e6fcf32e5a3b
6
+ metadata.gz: 587323c57caac3e53af1da24cfeee47df18ff738516d8fd2862d37a547c6e864cf5653c8b43427ec58aa47be3f2e958c991208b36de098c5ffc9503f2c64a0a2
7
+ data.tar.gz: f5380cfdca6a4f60833ab57fc8465715b546415fa4f6ed5781b6bb24653ce324d2b6d928f9a5ff87b4deead145391303c1e805bf0fbff238b9ef1c7024a1f4aa
data/.rubocop.yml CHANGED
@@ -19,6 +19,7 @@ Metrics/AbcSize:
19
19
  Metrics/MethodLength:
20
20
  Exclude:
21
21
  - lib/json/repairer.rb
22
+ - benchmark/**/*
22
23
 
23
24
  Metrics/CyclomaticComplexity:
24
25
  Exclude:
data/CHANGELOG.md CHANGED
@@ -1,5 +1,32 @@
1
1
  # Changes
2
2
 
3
+ ### 2026-05-12 (0.7.0)
4
+
5
+ * `JSON.repair` now always returns canonical JSON via
6
+ `JSON.generate`. When the input is already valid JSON, stdlib
7
+ `JSON.parse` handles it directly; when it isn't, the repairer
8
+ produces an intermediate string that's then re-parsed and serialized
9
+ the same way. Both paths converge on the same output for any given
10
+ input, so `JSON.repair(json)` and
11
+ `JSON.repair(json, skip_json_loads: true)` agree on result and only
12
+ differ in how they got there.
13
+ * **Breaking:** outputs are now canonical instead of preserving the
14
+ input's exact formatting. Whitespace is collapsed
15
+ (`'{"a": 1}'` → `'{"a":1}'`), numbers are normalized
16
+ (`2300e3` → `2300000.0`, `-0` → `0`), `\uXXXX` escapes are decoded
17
+ to their literal characters, `\/` is unescaped to `/`, and objects
18
+ with duplicate keys are collapsed to the last-write-wins form
19
+ (`{"a":1,"a":2}` → `{"a":2}`). Callers that need a parsed Ruby
20
+ value can opt out of the final `JSON.generate` step with
21
+ `return_objects: true`.
22
+ * `skip_json_loads:` keyword argument added (default `false`,
23
+ mirroring Python's
24
+ [`json_repair`](https://github.com/mangiucugna/json_repair)
25
+ option). Passing `true` skips the stdlib `JSON.parse` fast attempt
26
+ and routes the input through the repairer first; the final output
27
+ is identical, so the option is purely a performance knob for
28
+ callers who know their input will need repair.
29
+
3
30
  ### 2026-05-12 (0.6.0)
4
31
 
5
32
  * `JSON.repair` accepts a `return_objects:` keyword argument. Pass
data/README.md CHANGED
@@ -26,7 +26,7 @@ require 'json/repair'
26
26
  # Example of repairing a JSON string
27
27
  broken_json = '{name: Alice, "age": 25,}'
28
28
  repaired_json = JSON.repair(broken_json)
29
- puts repaired_json # Outputs: {"name": "Alice", "age": 25}
29
+ puts repaired_json # Outputs: {"name":"Alice","age":25}
30
30
  ```
31
31
 
32
32
  The `repair` method takes a string containing JSON data and returns a corrected version of this string, ensuring it is valid JSON.
@@ -38,6 +38,21 @@ JSON.repair('{a: 1, b: [2, 3,]}', return_objects: true)
38
38
  # => {"a" => 1, "b" => [2, 3]}
39
39
  ```
40
40
 
41
+ ### Canonical output
42
+
43
+ `JSON.repair` returns canonical JSON via `JSON.generate`. When the input is already valid, stdlib `JSON.parse` handles it; otherwise the repairer fixes it up and the result is re-serialized the same way. Either way, the output is the canonical form of the parsed value — whitespace is collapsed, numbers are normalized, `\uXXXX` escapes are decoded to literal characters, and objects with duplicate keys collapse to last-write-wins.
44
+
45
+ ```ruby
46
+ JSON.repair('{"a": 1}') # => '{"a":1}'
47
+ JSON.repair('{a:1}') # => '{"a":1}'
48
+ JSON.repair('2300e3') # => '2300000.0'
49
+ JSON.repair('{"a":1,"a":2}') # => '{"a":2}'
50
+ ```
51
+
52
+ If you need the parsed Ruby value instead of a string, pass `return_objects: true` (covered above).
53
+
54
+ `skip_json_loads: true` skips the stdlib `JSON.parse` attempt and routes the input straight through the repairer. The output is the same; the option is purely a performance knob for callers who know their input will need repair.
55
+
41
56
  ## Command line
42
57
 
43
58
  The gem ships a `json-repair` executable. It reads from stdin or a file and writes to stdout, `--output FILE`, or back over the input file with `--overwrite`.
@@ -57,6 +72,8 @@ Run `json-repair --help` for the full list of options.
57
72
 
58
73
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
59
74
 
75
+ Run `bundle exec rake bench` for a `benchmark-ips` regression baseline across four canned scenarios (valid mixed JSON, broken LLM-style output, a large array, deeply nested objects). The harness lives under `benchmark/` and is not shipped in the published gem.
76
+
60
77
  To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
61
78
 
62
79
  ## Contributing
data/Rakefile CHANGED
@@ -19,4 +19,9 @@ task :steep do
19
19
  sh 'bundle exec steep check'
20
20
  end
21
21
 
22
+ desc 'Run benchmark/run.rb (regression baseline for JSON.repair)'
23
+ task :bench do
24
+ ruby '-Ilib', 'benchmark/run.rb'
25
+ end
26
+
22
27
  task default: %i[spec rubocop rbs steep]
@@ -75,8 +75,7 @@ module JSON
75
75
  elsif (output_path = @output_path)
76
76
  File.write(output_path, repaired)
77
77
  else
78
- @stdout.write(repaired)
79
- @stdout.write("\n") unless repaired.end_with?("\n")
78
+ @stdout.write(repaired, "\n")
80
79
  end
81
80
  end
82
81
 
@@ -2,6 +2,6 @@
2
2
 
3
3
  module JSON
4
4
  module Repair
5
- VERSION = '0.6.0'
5
+ VERSION = '0.7.0'
6
6
  end
7
7
  end
data/lib/json/repair.rb CHANGED
@@ -15,8 +15,20 @@ module JSON
15
15
  end
16
16
  end
17
17
 
18
- def self.repair(json, return_objects: false)
19
- repaired = Repairer.new(json).repair
20
- return_objects ? JSON.parse(repaired) : repaired
18
+ def self.repair(json, return_objects: false, skip_json_loads: false)
19
+ parsed = skip_json_loads ? repaired_parse(json) : tolerant_parse(json)
20
+ return_objects ? parsed : JSON.generate(parsed)
21
21
  end
22
+
23
+ def self.tolerant_parse(json)
24
+ JSON.parse(json)
25
+ rescue JSON::ParserError
26
+ repaired_parse(json)
27
+ end
28
+ private_class_method :tolerant_parse
29
+
30
+ def self.repaired_parse(json)
31
+ JSON.parse(Repairer.new(json).repair)
32
+ end
33
+ private_class_method :repaired_parse
22
34
  end
data/sig/json/repair.rbs CHANGED
@@ -9,7 +9,13 @@ module JSON
9
9
  VERSION: ::String
10
10
  end
11
11
 
12
- def self.repair: (::String json) -> ::String
13
- | (::String json, return_objects: false) -> ::String
14
- | (::String json, return_objects: true) -> untyped
12
+ def self.repair: (::String json, return_objects: false, ?skip_json_loads: bool) -> ::String
13
+ | (::String json, return_objects: true, ?skip_json_loads: bool) -> untyped
14
+ | (::String json, ?skip_json_loads: bool) -> ::String
15
+
16
+ private
17
+
18
+ def self.tolerant_parse: (::String json) -> untyped
19
+
20
+ def self.repaired_parse: (::String json) -> untyped
15
21
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: json-repair
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.0
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aleksandr Zykov