JsonToMarkdown 26.9.4906

dotnet add package JsonToMarkdown --version 26.9.4906
                    
NuGet\Install-Package JsonToMarkdown -Version 26.9.4906
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="JsonToMarkdown" Version="26.9.4906" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="JsonToMarkdown" Version="26.9.4906" />
                    
Directory.Packages.props
<PackageReference Include="JsonToMarkdown" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add JsonToMarkdown --version 26.9.4906
                    
#r "nuget: JsonToMarkdown, 26.9.4906"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package JsonToMarkdown@26.9.4906
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=JsonToMarkdown&version=26.9.4906
                    
Install as a Cake Addin
#tool nuget:?package=JsonToMarkdown&version=26.9.4906
                    
Install as a Cake Tool

JsonToMarkdown

Convert one JSON document into deterministic, human-readable GitHub Flavored Markdown.

A modern C# / .NET 10 port of json-to-md. The conversion core produces byte-identical output to the reference TypeScript and Go implementations — verified against the shared corpus/ fixtures on every build. Output is a readable projection rather than a reversible serialization format. Every document begins with a # Results heading and uses canonical spacing: LF endings, one blank line between blocks, no trailing spaces, one final newline.

Why convert JSON to Markdown?

If you feed JSON into an LLM, you pay for its punctuation. Every {, }, ", :, and , is tokens spent on structure the model does not need to read the data. Converting the same document to Markdown headings, lists, and tables is measurably cheaper, tokenizes more efficiently, and stays human-readable in prompts, agent memory, and RAG context.

The tradeoff: this is a one-way, human-facing projection, not a reversible serialization. When a downstream step must parse, validate, or store the data, keep the JSON.

Install

dotnet add package JsonToMarkdown

Targets .NET 10. No third-party runtime dependencies (uses System.Text.Json).

Use

using JsonToMarkdown;

// Untrusted serialized JSON text — byte-identical to the reference implementations.
string md = JsonMarkdown.ConvertText("""{ "hello": "world" }""");

// # Results
//
// ## hello
//
// world

There are two entry points, plus a typed exception. All conversions are pure, never mutate their input, share no state, and are safe to run concurrently.

JsonMarkdown.ConvertText(string source)

Accepts untrusted serialized JSON text. A dedicated parser reads it without executing caller code and preserves each number's original spelling, object-member order, and array order. It rejects duplicate member names and reports UTF-16 source locations. This is the byte-identical parity path.

JsonMarkdown.ConvertText("9007199254740993"); // preserved exactly
JsonMarkdown.ConvertText("1.00");              // "1.00" (lexeme preserved)

JsonMarkdown.ConvertValue(...) — the System.Text.Json path

Accepts an already-parsed System.Text.Json object model. Overloads take a JsonNode or a JsonElement. Because System.Text.Json preserves the raw numeric token, numbers keep their original spelling here too.

using System.Text.Json.Nodes;

JsonNode? node = JsonNode.Parse("""{ "hello": "world" }""");
string md = JsonMarkdown.ConvertValue(node);

// Convenience: read a JSON object from a string with System.Text.Json, then convert.
string md2 = JsonMarkdown.ConvertValueFromText("""{ "hello": "world" }""");

Errors

Conversion fails atomically at the first error in encounter order and never returns partial Markdown, throwing JsonToMarkdownException:

try
{
    JsonMarkdown.ConvertText("""{"name":"a","name":"b"}""");
}
catch (JsonToMarkdownException e)
{
    e.Code;          // JsonToMarkdownErrorCode.DuplicateMemberName
    e.Message;       // human-readable
    e.Location;      // { Offset, Line, Column } for serialized syntax failures (UTF-16 units)
    e.FirstLocation; // first occurrence, for duplicate member names
    e.Pointer;       // JSON Pointer, when the invalid value is locatable
}

Codes: InvalidJsonSyntax, DuplicateMemberName, InvalidParsedValue, CyclicReference, SparseArray (the last cannot occur from System.Text.Json input).

How values render

Input Rendering
Object keys Headings H2–H6, then nested unordered lists once nesting passes H6
Array of objects (a Tabular Array) One GFM table; also when nested inside a list
Any other array Unordered list in source order
Non-empty container in a table cell Link to a Detail Section headed by the value's JSON Pointer, preceded by a --- thematic break
String Escaped literal text; never injects Markdown or HTML
Whole-string absolute http(s) URL Markdown link
null / "" / [] / {} `null` / `""` / `[]` / `{}` (each kept distinct from a missing table cell)
JsonMarkdown.ConvertText("""{"table1":[{"age":14,"degrees":[{"name":"B-Degree","year":"2023"}]}]}""");
# Results

## table1

| age | degrees                              |
| --- | ------------------------------------ |
| 14  | [/table1/0/degrees](#table10degrees) |

---

### /table1/0/degrees

| name     | year |
| -------- | ---- |
| B-Degree | 2023 |

There is no converter-defined input-size, nesting-depth, or table-size limit; parsing, validation, and rendering are iterative, so deeply nested documents do not overflow the stack.

Design notes

  • UTF-16 fidelity. The reference implementation operates on UTF-16 code units, and so does this port — C# char/string are UTF-16, so source offsets, escaping, and surrogate handling map directly, keeping output byte-identical.
  • Heading anchors. Detail-section links reproduce github-slugger exactly, including JS-style toLowerCase with the Unicode Final_Sigma rule and the code-point strip table (see SlugRanges.cs, generated from the reference Go data).
  • Numeric lexemes. Both entry points preserve a number's original token (1.00, 2E+3, 9007199254740993) rather than round-tripping through a floating-point value.

Repository layout

  • Src/JsonToMarkdown/ — the library.
  • Src/JsonToMarkdown.Tests/ — MSTest suite: the shared parity corpus/, plus Markdig-based checks that the output is valid GFM.
  • corpus/ — the byte-identical contract of record, shared with the reference implementations.
  • reference/ — the original TypeScript and Go sources, kept for reference.
  • .devops/build-nuget.yml — Azure DevOps pipeline that packs and publishes the NuGet package.

Development

dotnet build  Src/JsonToMarkdown.sln -c Release
dotnet test   Src/JsonToMarkdown.sln -c Release

License

MIT. Ported from json-to-md by Raj Nandan Sharma (MIT).

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net10.0

    • No dependencies.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
26.9.4906 91 9/9/2026
26.7.2877 107 7/23/2026
26.7.2876 103 7/23/2026
26.7.2874 105 7/23/2026