-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathMetaJson.cs
More file actions
86 lines (75 loc) · 3.26 KB
/
Copy pathMetaJson.cs
File metadata and controls
86 lines (75 loc) · 3.26 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
using System.Text.Json;
using System.Text.Json.Serialization;
namespace ShellDocs.Core;
public class MetaJson
{
[JsonPropertyName("title")]
public string? Title { get; set; }
[JsonPropertyName("pages")]
public List<MetaJsonEntry> Pages { get; set; } = new();
// Slugs of pages or subfolders that should route (URLs resolve) but not
// appear in the sidebar tree. Useful for landing pages reached only via
// the package selector, private drafts, or archived content.
[JsonPropertyName("hidden")]
public List<string> Hidden { get; set; } = new();
private static readonly JsonSerializerOptions Options = new()
{
PropertyNameCaseInsensitive = true,
ReadCommentHandling = JsonCommentHandling.Skip,
AllowTrailingCommas = true,
Converters = { new MetaJsonEntryConverter() }
};
public static MetaJson? Parse(string json)
{
if (string.IsNullOrWhiteSpace(json)) return null;
return JsonSerializer.Deserialize<MetaJson>(json, Options);
}
}
public abstract class MetaJsonEntry { }
public class MetaJsonPageRef : MetaJsonEntry { public required string Slug { get; init; } }
public class MetaJsonDivider : MetaJsonEntry { }
public class MetaJsonSubsection : MetaJsonEntry
{
public required string Title { get; init; }
public List<MetaJsonEntry> Pages { get; init; } = new();
}
/*
Each entry in meta.json's "pages" array can be:
- a string slug ("button")
- the literal "---" for a section divider
- an object { "title": "Data Display", "pages": [...] } for a subsection
Custom converter dispatches on the JSON token type.
*/
internal class MetaJsonEntryConverter : JsonConverter<MetaJsonEntry>
{
public override MetaJsonEntry? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType == JsonTokenType.String)
{
var value = reader.GetString() ?? "";
return value == "---" ? new MetaJsonDivider() : new MetaJsonPageRef { Slug = value };
}
if (reader.TokenType == JsonTokenType.StartObject)
{
using var doc = JsonDocument.ParseValue(ref reader);
var root = doc.RootElement;
var title = root.TryGetProperty("title", out var t) ? t.GetString() ?? "" : "";
var pages = new List<MetaJsonEntry>();
if (root.TryGetProperty("pages", out var p) && p.ValueKind == JsonValueKind.Array)
{
foreach (var el in p.EnumerateArray())
{
var elJson = el.GetRawText();
var childReader = new Utf8JsonReader(System.Text.Encoding.UTF8.GetBytes(elJson));
childReader.Read();
var child = Read(ref childReader, typeof(MetaJsonEntry), options);
if (child is not null) pages.Add(child);
}
}
return new MetaJsonSubsection { Title = title, Pages = pages };
}
throw new JsonException($"Unexpected token {reader.TokenType} in meta.json entry.");
}
public override void Write(Utf8JsonWriter writer, MetaJsonEntry value, JsonSerializerOptions options)
=> throw new NotSupportedException("Writing meta.json entries not supported.");
}