Dependencies/Pixie/Pixie/Transforms/DiagnosticExtractor.cs
using System;
using System.Collections.Generic;
using WasmBox.Pixie.Markup;
namespace WasmBox.Pixie.Transforms {
/// <summary>
/// A transformation that turns log entries into diagnostics.
/// </summary>
public sealed class DiagnosticExtractor {
/// <summary>
/// Creates a diagnostic extractor.
/// </summary>
/// <param name="defaultOrigin">
/// The default origin to use, for when a log entry
/// does not specify an origin.
/// </param>
/// <param name="defaultKind">
/// The kind of diagnostic to provide.
/// </param>
/// <param name="defaultThemeColor">
/// The diagnostic theme color.
/// </param>
/// <param name="defaultTitle">
/// The diagnostic title.
/// </param>
public DiagnosticExtractor(
MarkupNode defaultOrigin,
string defaultKind,
Color defaultThemeColor,
MarkupNode defaultTitle) {
this.DefaultOrigin = defaultOrigin;
this.DefaultKind = defaultKind;
this.DefaultThemeColor = defaultThemeColor;
this.DefaultTitle = defaultTitle;
}
/// <summary>
/// Gets the default origin to use, for when a log entry
/// does not specify an origin.
/// </summary>
/// <returns>The default origin.</returns>
public MarkupNode DefaultOrigin { get; private set; }
/// <summary>
/// Gets the default kind of diagnostic to produce.
/// </summary>
/// <returns>The default kind of diagnostic.</returns>
public string DefaultKind { get; private set; }
/// <summary>
/// Gets the default theme color for diagnostics.
/// </summary>
/// <returns>The default theme color for diagnostics.</returns>
public Color DefaultThemeColor { get; private set; }
/// <summary>
/// Gets the default title for diagnostics.
/// </summary>
/// <returns>The default title for diagnostics.</returns>
public MarkupNode DefaultTitle { get; private set; }
/// <summary>
/// Transforms a markup tree to include a diagnostic.
/// </summary>
/// <param name="tree">The tree to transform.</param>
/// <returns>A transformed tree.</returns>
public MarkupNode Transform(MarkupNode tree) {
var visitor = new DiagnosticExtractingVisitor(this);
return visitor.Transform(tree);
}
private static Dictionary<Severity, string> defaultKinds =
new Dictionary<Severity, string>() { { Severity.Info, "info" }, { Severity.Message, "message" }, { Severity.Warning, "warning" }, { Severity.Error, "error" }
};
private static Dictionary<Severity, Color> defaultColors =
new Dictionary<Severity, Color>() { { Severity.Info, Colors.Green }, { Severity.Message, Colors.Green }, { Severity.Warning, Colors.Yellow }, { Severity.Error, Colors.Red }
};
/// <summary>
/// Transforms a log entry to include a diagnostic.
/// </summary>
/// <param name="entry">The log entry to transform.</param>
/// <param name="defaultOrigin">
/// The default origin of a diagnostic. This is typically the
/// name of the application.</param>
/// <returns>A transformed log entry.</returns>
public static LogEntry Transform(LogEntry entry, MarkupNode defaultOrigin) {
var extractor = new DiagnosticExtractor(
defaultOrigin,
defaultKinds[entry.Severity],
defaultColors[entry.Severity],
new Text(""));
return new LogEntry(entry.Severity, extractor.Transform(entry.Contents));
}
}
/// <summary>
/// A node visitor that helps turn log entries into diagnostics.
/// </summary>
internal sealed class DiagnosticExtractingVisitor : MarkupVisitor {
public DiagnosticExtractingVisitor(DiagnosticExtractor extractor) {
this.extractor = extractor;
}
public DiagnosticExtractor extractor;
private MarkupNode title;
private MarkupNode origin;
private bool foundText;
private bool foundExistingDiagnostic;
private bool FoundEverything =>
foundExistingDiagnostic
|| (title != null
&& origin != null);
/// <inheritdoc/>
protected override bool IsOfInterest(MarkupNode node) {
return !FoundEverything
&& (node is Title
|| node is Text
|| node is HighlightedSource
|| node is Diagnostic);
}
/// <inheritdoc/>
protected override MarkupNode VisitInteresting(MarkupNode node) {
if (!foundText) {
if (node is Title) {
title = ((Title)node).Contents;
foundText = true;
return new Text("");
}
else if (node is Text) {
foundText = true;
return node;
}
else if (node is Diagnostic) {
// A top-level diagnostic is just what we're looking for.
foundExistingDiagnostic = true;
return node;
}
}
if (origin == null && node is HighlightedSource) {
var src = (HighlightedSource)node;
origin = new SourceReference(src.HighlightedSpan);
return node;
}
return VisitUninteresting(node);
}
/// <summary>
/// Transforms a node to include a diagnostic.
/// </summary>
/// <param name="node">The node to transform.</param>
/// <returns>A transformed node.</returns>
public MarkupNode Transform(MarkupNode node) {
var visited = Visit(node);
if (foundExistingDiagnostic) {
return visited;
}
else {
return new Diagnostic(
origin ?? extractor.DefaultOrigin,
extractor.DefaultKind,
extractor.DefaultThemeColor,
title ?? extractor.DefaultTitle,
visited);
}
}
}
}