json-repair 0.11.1 → 0.11.2

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: 288e3502829f51d11dbf2c3a9ab45f04dd44a1fa9ae5e00c1537f47c215aad96
4
- data.tar.gz: 1ab99e5121ef3e73066157569bd85379a527cc1f44ecd7087d4f058133c4fcf0
3
+ metadata.gz: 2d7b2f30c2451f62471beabed342ff8360f644e4ae703fa3e0f5490e44d4f0d1
4
+ data.tar.gz: 254abaa4ab104a0cc6650d02f099ebb00b0600ef213b00866da266159b6c1a37
5
5
  SHA512:
6
- metadata.gz: ffc4cd085d9a6aa5b45f3ee605a0fa043e20c68d63fdaab5c736acecbb17f160066d4412a76496300614545577d74d5ca4b232d4354adf625913753f8c0e8477
7
- data.tar.gz: 190ea601a010b401fdf0c6aa52670a030ce81d39ebcd1af1f81c9fb2399baf6d074f3135b3b05814d1bcfcd24db53321a779b760c8eebe8d5a9ce2e029476754
6
+ metadata.gz: bfd417574888a7ff44a03870f48ab6e02c7bb7ae80189262e093425ba52e3943982f6ab36170c1cac6a3871e3d3379469b8319bbaa6defe8a0d473a7be6fe2a9
7
+ data.tar.gz: 208611ef2a09d4e3a5c91afe98334dfc7443a3db56de9624cfa82a3dea1e0c0480de18227646a96dac3c46f64af526e229f70dd9de4cd41cc1160a703b132a0b
data/.rubocop.yml CHANGED
@@ -1,5 +1,15 @@
1
+ # Merge our Exclude lists with RuboCop's defaults (vendor/**/*, tmp/**/*, …)
2
+ # instead of replacing them — CI vendors gems into vendor/bundle, which
3
+ # RuboCop must keep skipping.
4
+ inherit_mode:
5
+ merge:
6
+ - Exclude
7
+
1
8
  AllCops:
2
9
  TargetRubyVersion: 3.0
10
+ Exclude:
11
+ # gitignored local planning notes and scratch tooling (see CLAUDE.md)
12
+ - docs/**/*
3
13
 
4
14
  Style/Documentation:
5
15
  Enabled: false
data/CHANGELOG.md CHANGED
@@ -1,6 +1,26 @@
1
1
  # Changes
2
2
 
3
- ### 2026-06-12 (0.11.1)
3
+ ### 2026-06-12 (0.11.2)
4
+
5
+ * Fix the 0.11.0 doubled-colon repair silently mangling objects with a
6
+ stray junk word between pairs. `{"value_1": true, COMMENT "value_2":
7
+ "data"}` returned `{"value_1":true,"COMMENT":"value_2\": \"data"}`
8
+ (the junk word became a key and swallowed the real pair), and
9
+ `{ "key": "value" COMMENT "key2": "value2" }` returned a single
10
+ glued string value. Both shapes now raise "Object key expected"
11
+ again at the same positions as upstream
12
+ [jsonrepair](https://github.com/josdejong/jsonrepair) v3.14.0,
13
+ restoring the pre-0.11.0 behavior: the merge is skipped when the
14
+ pair already needed a missing-colon repair or the value string was
15
+ itself salvaged by the unescaped-quote repair — signals that the
16
+ pair was malformed in a way the merge would compound, not fix. The
17
+ salvage signal survives string concatenation: in
18
+ `{"a": "b" x "c" + "d": "e"}` the `+ "d"` segment no longer clears
19
+ it (caught in review by Copilot). All
20
+ 0.11.0 repairs (canonical, greedy, escaped quotes, unquoted
21
+ keys/values) are unchanged. Go and Python `json_repair` instead
22
+ drop the junk word; we deliberately keep raising rather than
23
+ silently discarding input (see the 0.11.0 note).
4
24
 
5
25
  * Fix a `TypeError` crash on input ending in a lone backslash inside a
6
26
  string: `"abc\` now repairs to `"abc"` (likewise `"\` → `""`,
@@ -2,6 +2,6 @@
2
2
 
3
3
  module JSON
4
4
  module Repair
5
- VERSION = '0.11.1'
5
+ VERSION = '0.11.2'
6
6
  end
7
7
  end
data/lib/json/repairer.rb CHANGED
@@ -32,6 +32,7 @@ module JSON
32
32
  @json = json
33
33
  @index = 0
34
34
  @output = +''
35
+ @repaired_unescaped_quote = false
35
36
  end
36
37
 
37
38
  def repair
@@ -295,8 +296,14 @@ module JSON
295
296
  end
296
297
 
297
298
  # repair: an object string value with unescaped quotes around a
298
- # colon, like {"a": "b": "c"}
299
- repair_doubled_colon if processed_value
299
+ # colon, like {"a": "b": "c"}. Skipped when this pair already
300
+ # needed a repair that makes the merge compound garbage: a
301
+ # missing colon (the "key" was a stray junk word, like
302
+ # {"v1": true, COMMENT "v2": "data"}) or a value glued together
303
+ # by the unescaped-quote repair (like
304
+ # {"k": "v" COMMENT "k2": "v2"}); both keep raising, matching
305
+ # upstream
306
+ repair_doubled_colon if processed_value && processed_colon && !@repaired_unescaped_quote
300
307
  end
301
308
 
302
309
  if @json[@index] == CLOSING_BRACE
@@ -315,9 +322,13 @@ module JSON
315
322
  # (the unescaped-quotes reading of the input). Greedy: keeps merging
316
323
  # while another `: "..."` follows. Only the string-colon-string
317
324
  # shape is repaired; anything else falls through to the regular
318
- # error paths. Divergence from upstream (which raises "Object key
319
- # expected" as of v3.14.0), matching the Go and Python json-repair
320
- # libraries on the canonical case.
325
+ # error paths. The call site additionally requires the pair's colon
326
+ # to be present in the input and the value string to have parsed
327
+ # without the unescaped-quote repair (@repaired_unescaped_quote) —
328
+ # when either repair already fired, the pair was malformed in a way
329
+ # this merge would compound, not fix. Divergence from upstream
330
+ # (which raises "Object key expected" as of v3.14.0), matching the
331
+ # Go and Python json-repair libraries on the canonical case.
321
332
  def repair_doubled_colon
322
333
  loop do
323
334
  colon = @index
@@ -399,6 +410,9 @@ module JSON
399
410
  # and fixing the string by inserting a quote there, or stopping at a
400
411
  # stop index detected in the first iteration.
401
412
  def parse_string(stop_at_delimiter: false, stop_at_index: -1)
413
+ # fresh parse (the backtracking re-invocations below rebuild the
414
+ # string from scratch, so they reset too); see repair_doubled_colon
415
+ @repaired_unescaped_quote = false
402
416
  skip_escape_chars = @json[@index] == BACKSLASH
403
417
  if skip_escape_chars
404
418
  # repair: remove the first escape character
@@ -508,6 +522,7 @@ module JSON
508
522
 
509
523
  # repair unescaped quote
510
524
  str = "#{str[...o_quote]}\\#{str[o_quote..]}"
525
+ @repaired_unescaped_quote = true
511
526
  elsif stop_at_delimiter && unquoted_string_delimiter?(@json[@index])
512
527
  # we're in the mode to stop the string at the first delimiter
513
528
  # because there is an end quote missing
@@ -807,7 +822,12 @@ module JSON
807
822
  # repair: remove the end quote of the first string
808
823
  @output = strip_last_occurrence(@output, '"', strip_remaining_text: true)
809
824
  start = @output.length
825
+ # the segments form one logical string value: keep the doubled-colon
826
+ # guard's flag set when an earlier segment needed the unescaped-quote
827
+ # repair (parse_string resets it on entry)
828
+ repaired_earlier_segment = @repaired_unescaped_quote
810
829
  parsed_str = parse_string
830
+ @repaired_unescaped_quote ||= repaired_earlier_segment
811
831
  @output = if parsed_str
812
832
  # repair: remove the start quote of the second string
813
833
  remove_at_index(@output, start, 1)
@@ -15,6 +15,8 @@ module JSON
15
15
 
16
16
  @output: ::String
17
17
 
18
+ @repaired_unescaped_quote: bool
19
+
18
20
  include Repair::StringUtils
19
21
 
20
22
  CONTROL_CHARACTERS: ::Hash[::String, "\\b" | "\\f" | "\\n" | "\\r" | "\\t"]
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.11.1
4
+ version: 0.11.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aleksandr Zykov