JsonRemedy (json_remedy v0.1.3)

View Source

A blazingly fast, Elixir-native JSON repair library.

JsonRemedy uses a layered architecture with binary pattern matching to intelligently repair malformed JSON strings while achieving superior performance.

This module provides the main API for JSON repair functionality. It supports multiple repair strategies and can handle various types of malformed JSON through a four-layer processing pipeline:

  • Layer 1: Content Cleaning (removes code fences, comments, extra text)
  • Layer 2: Structural Repair (fixes missing braces, brackets, etc.)
  • Layer 3: Syntax Normalization (quotes, booleans, commas, colons)
  • Layer 4: Validation (validates and parses the final JSON)

Examples

iex> JsonRemedy.repair(~s|{name: "Alice", age: 30, active: True}|)
{:ok, %{"name" => "Alice", "age" => 30, "active" => true}}

iex> JsonRemedy.repair_to_string(~s|[1, 2, 3,]|)
{:ok, "[1,2,3]"}

iex> JsonRemedy.repair(~s|{incomplete: "data"|, logging: true)
{:ok, %{"incomplete" => "data"}, [
  %{layer: :structural_repair, action: "added missing closing brace", position: 18, original: nil, replacement: "}"},
  %{layer: :syntax_normalization, action: "quoted unquoted key", position: 1, original: nil, replacement: nil}
]}

Summary

Functions

Returns information about what repairs would be applied to the input.

Checks if a string appears to be malformed JSON that JsonRemedy can fix.

Repairs JSON content directly from a file.

Repairs malformed JSON and returns the parsed Elixir term.

Creates a stream that repairs JSON objects from an input stream.

Repairs malformed JSON and returns the fixed JSON string.

Repairs malformed JSON with detailed debugging information.

Types

json_value()

@type json_value() ::
  nil
  | boolean()
  | number()
  | String.t()
  | [json_value()]
  | %{required(String.t()) => json_value()}

option()

@type option() ::
  {:logging, boolean()}
  | {:debug, boolean()}
  | {:jason_options, keyword()}
  | {:fast_path_optimization, boolean()}

repair_action()

@type repair_action() :: %{layer: atom(), action: String.t()}

repair_result()

@type repair_result() :: {:ok, json_value()} | {:error, String.t()}

repair_result_with_logs()

@type repair_result_with_logs() ::
  {:ok, json_value(), [repair_action()]} | {:error, String.t()}

Functions

analyze(json_string)

@spec analyze(binary()) :: {:ok, [repair_action()]} | {:error, String.t()}

Returns information about what repairs would be applied to the input.

Processes through the pipeline but returns detailed information about what each layer would do without actually applying the repairs.

Examples

iex> JsonRemedy.analyze(~s|{name: 'Alice', active: True}|)
{:ok, [
  %{layer: :syntax_normalization, action: "normalized boolean", position: 24, original: nil, replacement: nil},
  %{layer: :syntax_normalization, action: "quoted unquoted key", position: 16, original: nil, replacement: nil},
  %{layer: :syntax_normalization, action: "normalized quotes", position: 7, original: nil, replacement: nil},
  %{layer: :syntax_normalization, action: "quoted unquoted key", position: 1, original: nil, replacement: nil}
]}

can_repair?(json_string)

@spec can_repair?(binary()) :: boolean()

Checks if a string appears to be malformed JSON that JsonRemedy can fix.

Returns true if the input has issues that JsonRemedy layers can address.

Examples

iex> JsonRemedy.can_repair?(~s|{"valid": true}|)
false

iex> JsonRemedy.can_repair?(~s|{name: "Alice"}|)
true

iex> JsonRemedy.can_repair?(~s/```json\n{"test": true}\n```/)
true

from_file(path, opts \\ [])

@spec from_file(Path.t(), [option()]) :: repair_result() | repair_result_with_logs()

Repairs JSON content directly from a file.

Reads the file and processes it through the JsonRemedy pipeline.

Examples

iex> JsonRemedy.from_file("config.json")
{:ok, %{"setting" => "value"}}

iex> JsonRemedy.from_file("nonexistent.json", logging: true)
{:error, "Could not read file: :enoent"}

repair(json_string, opts \\ [])

@spec repair(binary(), [option()]) :: repair_result() | repair_result_with_logs()

Repairs malformed JSON and returns the parsed Elixir term.

Processes the input through all four layers of the JsonRemedy pipeline to fix common JSON formatting issues and return a parsed Elixir data structure.

Options

  • logging: true - Returns repair actions taken as third element in tuple
  • debug: true - Returns detailed step-by-step debugging information
  • jason_options: [] - Options to pass to Jason for final parsing
  • fast_path_optimization: true - Enable fast path for already valid JSON (default)

Examples

iex> JsonRemedy.repair(~s|{"name": "John", "age": 30}|)
{:ok, %{"name" => "John", "age" => 30}}

iex> JsonRemedy.repair(~s|{name: "John", age: 30, active: True}|)
{:ok, %{"name" => "John", "age" => 30, "active" => true}}

iex> JsonRemedy.repair(~s|[1, 2, 3,]|, logging: true)
{:ok, [1, 2, 3], [%{layer: :syntax_normalization, action: "removed trailing comma", position: 8, original: nil, replacement: nil}]}

iex> JsonRemedy.repair(~s/```json\n{"valid": true}\n```/)
{:ok, %{"valid" => true}}

repair_stream(stream, opts \\ [])

@spec repair_stream(Enumerable.t(), [option()]) :: Enumerable.t()

Creates a stream that repairs JSON objects from an input stream.

Useful for processing large files or real-time data streams. Each item in the stream is processed independently through the JsonRemedy pipeline.

Examples

"large_file.jsonl"
|> File.stream!()
|> JsonRemedy.repair_stream()
|> Stream.each(&IO.inspect/1)
|> Stream.run()

repair_to_string(json_string, opts \\ [])

@spec repair_to_string(binary(), [option()]) :: {:ok, binary()} | {:error, String.t()}

Repairs malformed JSON and returns the fixed JSON string.

Like repair/2, but returns the repaired JSON as a string rather than parsing it.

Examples

iex> JsonRemedy.repair_to_string(~s|{name: "Alice"}|)
{:ok, ~s|{"name":"Alice"}|}

iex> JsonRemedy.repair_to_string(~s|[1, 2, 3,]|)
{:ok, "[1,2,3]"}

iex> JsonRemedy.repair_to_string(~s/```json\n{"test": true}\n```/)
{:ok, ~s|{"test":true}|}

repair_with_debug(json_string, opts \\ [])

@spec repair_with_debug(binary(), [option()]) ::
  {:ok, json_value(),
   %{
     steps: [map()],
     total_repairs: non_neg_integer(),
     processing_time_us: non_neg_integer()
   }}
  | {:error, String.t(),
     %{
       steps: [map()],
       total_repairs: non_neg_integer(),
       processing_time_us: non_neg_integer()
     }}

Repairs malformed JSON with detailed debugging information.

Returns comprehensive information about each step of the repair process, including what each layer attempted to do and why it succeeded or failed.

Examples

iex> {:ok, result, debug} = JsonRemedy.repair_with_debug(~s|{name: 'Alice', active: True}|)
iex> result
%{"name" => "Alice", "active" => true}
iex> debug.total_repairs
4
iex> length(debug.steps)
4