Getting started

edit

This page uses JSON. Every language works the same way: replace Json by the name of your language in the type names.

Install the package

Add the package of the language you parse to a project:

dotnet package add Meziantou.Framework.Language.Json

It brings Meziantou.Framework.Language, the package every language shares.

Parse a document

JsonSyntaxTree.ParseText parses a string. The tree keeps every character, comments and trailing commas included, so writing it back gives the input exactly:

var tree = JsonSyntaxTree.ParseText("""
{
  // the name of the thing
  "name": "value",
  "items": [1, 2,],
}
""");

// Comments and trailing commas are accepted, so there is nothing to report here.
Assert.Empty(tree.GetDiagnostics());

// And the text comes back exactly as it went in.
Assert.Equal(tree.GetText().Text, tree.GetRoot().ToFullString());

GetText() returns the text the tree was parsed from, and GetRoot() the root node: a JsonDocumentSyntax. ToFullString() writes a node back as text, with its whitespace and comments. To write it to a file or a stream, pass a TextWriter to WriteTo.

Pass the path of the file as the second argument of ParseText: the tree keeps it in FilePath, so you can report problems with the file they come from.

Read a value

The nodes have a property for each of their parts. Here, the root holds an object, whose members have a name and a value:

var tree = JsonSyntaxTree.ParseText("""{ "name": "value" }""");
var name = ((JsonObjectSyntax)tree.GetRoot().Value!).GetMember("name");
Assert.Equal("value", ((JsonStringSyntax)name!.Value).Value);

See Nodes and tokens to walk a tree and find the node at a position.

Report the problems

Parsing never throws: invalid text gives a tree too, and GetDiagnostics() says what is wrong and where. Lines and columns are zero-based:

var messages = new List<string>();
foreach (var diagnostic in JsonSyntaxTree.ParseText("{\"a\": }").GetDiagnostics())
{
    var line = diagnostic.Location.GetLineSpan().Start;
    messages.Add($"{diagnostic.Id} ({line.Line},{line.Character}): {diagnostic.Message}");
}

Assert.Equal(["JSON0007 (0,6): Expected a JSON value."], messages);

See Diagnostics.

Change a value

Trees are immutable: ReplaceNode returns a new root, in which only the replaced node differs. The rest of the text, spaces and comments included, is kept as it was:

var tree = JsonSyntaxTree.ParseText("""{ "version": "1.0.0", "other": 1 }""");
var version = ((JsonObjectSyntax)tree.GetRoot().Value!).GetMember("version")!;

JsonDocumentSyntax updated = tree.GetRoot().ReplaceNode(version.Value, SyntaxFactory.JsonString("2.0.0"));

Assert.Equal("""{ "version": "2.0.0", "other": 1 }""", updated.ToFullString());

SyntaxFactory builds new nodes, and writes them so that they read back as the value you gave. See Editing trees.

Next steps