Skip to content

Commit

Permalink
Fixed JSON to YAML Converter bugs
Browse files Browse the repository at this point in the history
  • Loading branch information
linkoid committed Sep 21, 2024
1 parent 4be696e commit 3040b39
Show file tree
Hide file tree
Showing 2 changed files with 146 additions and 97 deletions.
215 changes: 121 additions & 94 deletions YetAnother.Web/JsonToYamlConverter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,32 +20,51 @@ public class JsonToYamlConverter
};

private EmitterSettings emitterSettings = new EmitterSettings(
bestIndent: 2,
bestIndent: 2,
bestWidth: 120,
isCanonical: false,
maxSimpleKeyLength: 120,
skipAnchorName: false,
indentSequences: false,
newLine: null)
{

};
newLine: null
);

public JToken ParseJson(string? json)
public IEnumerable<JToken> ParseJson(string? json)
{
return JToken.Parse(json ?? "", jsonLoadSettings);
var tokens = new List<JToken>();
var reader = new JsonTextReader(new StringReader(json));

Check warning on line 35 in YetAnother.Web/JsonToYamlConverter.cs

View workflow job for this annotation

GitHub Actions / build

Possible null reference argument for parameter 's' in 'StringReader.StringReader(string s)'.
tokens.Add(JToken.Load(reader, jsonLoadSettings));
while (reader.Read())
{
tokens.Add(JToken.Load(reader, jsonLoadSettings));
}
return tokens;
}

public string ConvertToYaml(JToken token)
public string ConvertToYaml(IEnumerable<JToken> tokens)
{
using var stringWriter = new StringWriter();
var emitter = new Emitter(stringWriter, emitterSettings);
emitter.Emit(new StreamStart());
emitter.Emit(new DocumentStart());

bool gotFirstNonComment = false;

try
{
EmitJTokenToYaml(emitter, token);
foreach (var token in tokens)
{
if (token.Type != JTokenType.Comment)
{
if (gotFirstNonComment)
{
emitter.Emit(new DocumentEnd(false));
emitter.Emit(new DocumentStart());
}
gotFirstNonComment = true;
}
EmitJTokenHierarchyToYaml(emitter, token);
}
}
catch (Exception ex)
{
Expand All @@ -57,9 +76,9 @@ public string ConvertToYaml(JToken token)
return stringWriter.ToString();
}

private void EmitJTokenToYaml(IEmitter emitter, JToken token, JTokenReader? reader = null)
private void EmitJTokenHierarchyToYaml(IEmitter emitter, JToken token)
{
reader ??= new JTokenReader(token);
var reader = new JTokenReader(token);

int previousLine = -1;
while (reader.Read())
Expand All @@ -71,91 +90,99 @@ private void EmitJTokenToYaml(IEmitter emitter, JToken token, JTokenReader? read
previousLine = currentLineNumber;
}

TagName tag = TagName.Empty;
EmitJTokenToYaml(emitter, reader, currentLineNumber, isOnNewLine, reader.CurrentToken);
}
}

switch (reader.TokenType)
{
case JsonToken.None:
break;

case JsonToken.StartObject:
tag = FailsafeSchema.Tags.Map;
JContainer jobject = (JContainer?)reader.CurrentToken ?? throw new JsonSerializationException();
MappingStyle mappingStyle = MappingStyle.Any;
if (jobject.Last?.GetLineNumber() == currentLineNumber)
{
mappingStyle = MappingStyle.Flow;
}
emitter.Emit(new MappingStart(AnchorName.Empty, tag, true, mappingStyle));
break;

case JsonToken.StartArray:
tag = FailsafeSchema.Tags.Seq;
JContainer jarray = (JContainer?)reader.CurrentToken ?? throw new JsonSerializationException();
SequenceStyle sequenceStyle = SequenceStyle.Any;
if (jarray.Last?.GetLineNumber() == currentLineNumber)
{
sequenceStyle = SequenceStyle.Flow;
}
emitter.Emit(new SequenceStart(AnchorName.Empty, TagName.Empty, true, sequenceStyle));
break;

case JsonToken.StartConstructor:
throw new NotSupportedException(reader.TokenType.ToString());
break;

case JsonToken.PropertyName:
tag = FailsafeSchema.Tags.Str;
EmitPropertyNameToYaml(emitter, reader.Value as string ?? string.Empty, reader.CurrentToken!);
break;

case JsonToken.Comment:
emitter.Emit(new Comment(reader.Value?.ToString() ?? string.Empty, !isOnNewLine));
break;

case JsonToken.Raw:
throw new NotSupportedException(reader.TokenType.ToString());
break;

case JsonToken.String:
EmitStringToYaml(emitter, reader.Value as string ?? string.Empty, reader.CurrentToken!);
break;

case JsonToken.Integer:
tag = JsonSchema.Tags.Int;
goto case JsonToken.Undefined;
case JsonToken.Float:
tag = JsonSchema.Tags.Float;
goto case JsonToken.Undefined;
case JsonToken.Boolean:
tag = JsonSchema.Tags.Bool;
goto case JsonToken.Undefined;
case JsonToken.Null:
tag = JsonSchema.Tags.Null;
goto case JsonToken.Undefined;
case JsonToken.Date:
tag = DefaultSchema.Tags.Timestamp;
goto case JsonToken.Undefined;
case JsonToken.Undefined:
emitter.Emit(new Scalar(AnchorName.Empty, tag, reader.Value?.ToString() ?? string.Empty,
ScalarStyle.Any, isPlainImplicit: true, isQuotedImplicit: true));
break;

case JsonToken.EndObject:
emitter.Emit(new MappingEnd());
break;

case JsonToken.EndArray:
emitter.Emit(new SequenceEnd());
break;

case JsonToken.EndConstructor:
case JsonToken.Bytes:
throw new NotSupportedException(reader.TokenType.ToString());
break;
private void EmitJTokenToYaml(IEmitter emitter, JsonReader reader, int currentLineNumber, bool isOnNewLine, JToken? currentToken = null)
{
TagName tag = TagName.Empty;
Console.WriteLine($"Token Type: {reader.TokenType}");

switch (reader.TokenType)
{
case JsonToken.None:
break;

case JsonToken.StartObject:
tag = FailsafeSchema.Tags.Map;
JContainer? jobject = (JContainer?)currentToken;
MappingStyle mappingStyle = MappingStyle.Any;
if (jobject?.Last?.GetLineNumber() == currentLineNumber)
{
mappingStyle = MappingStyle.Flow;
}
emitter.Emit(new MappingStart(AnchorName.Empty, tag, true, mappingStyle));
break;

case JsonToken.StartArray:
tag = FailsafeSchema.Tags.Seq;
JContainer? jarray = (JContainer?)currentToken;
SequenceStyle sequenceStyle = SequenceStyle.Any;
if (jarray?.Last?.GetLineNumber() == currentLineNumber)
{
sequenceStyle = SequenceStyle.Flow;
}
emitter.Emit(new SequenceStart(AnchorName.Empty, TagName.Empty, true, sequenceStyle));
break;

case JsonToken.StartConstructor:
throw new NotSupportedException(reader.TokenType.ToString());
break;

Check warning on line 131 in YetAnother.Web/JsonToYamlConverter.cs

View workflow job for this annotation

GitHub Actions / build

Unreachable code detected

case JsonToken.PropertyName:
tag = FailsafeSchema.Tags.Str;
EmitPropertyNameToYaml(emitter, reader.Value as string ?? string.Empty, currentToken);

Check warning on line 135 in YetAnother.Web/JsonToYamlConverter.cs

View workflow job for this annotation

GitHub Actions / build

Possible null reference argument for parameter 'token' in 'void JsonToYamlConverter.EmitPropertyNameToYaml(IEmitter emitter, string str, JToken token)'.
break;

case JsonToken.Comment:
Console.WriteLine($"Got a comment {(isOnNewLine ? "newline" : "inline")}: {reader.Value?.ToString()}");
emitter.Emit(new Comment(reader.Value?.ToString() ?? string.Empty, !isOnNewLine));
break;

case JsonToken.Raw:
throw new NotSupportedException(reader.TokenType.ToString());
break;

Check warning on line 145 in YetAnother.Web/JsonToYamlConverter.cs

View workflow job for this annotation

GitHub Actions / build

Unreachable code detected

case JsonToken.String:
EmitStringToYaml(emitter, reader.Value as string ?? string.Empty, currentToken);

Check warning on line 148 in YetAnother.Web/JsonToYamlConverter.cs

View workflow job for this annotation

GitHub Actions / build

Possible null reference argument for parameter 'token' in 'void JsonToYamlConverter.EmitStringToYaml(IEmitter emitter, string str, JToken token)'.
break;

case JsonToken.Integer:
tag = JsonSchema.Tags.Int;
goto case JsonToken.Undefined;
case JsonToken.Float:
tag = JsonSchema.Tags.Float;
goto case JsonToken.Undefined;
case JsonToken.Boolean:
tag = JsonSchema.Tags.Bool;
goto case JsonToken.Undefined;
case JsonToken.Null:
tag = JsonSchema.Tags.Null;
goto case JsonToken.Undefined;
case JsonToken.Date:
tag = DefaultSchema.Tags.Timestamp;
goto case JsonToken.Undefined;
case JsonToken.Undefined:
emitter.Emit(new Scalar(AnchorName.Empty, tag, reader.Value?.ToString() ?? string.Empty,
ScalarStyle.Any, isPlainImplicit: true, isQuotedImplicit: true));
break;

case JsonToken.EndObject:
emitter.Emit(new MappingEnd());
break;

case JsonToken.EndArray:
emitter.Emit(new SequenceEnd());
break;

case JsonToken.EndConstructor:
case JsonToken.Bytes:
throw new NotSupportedException(reader.TokenType.ToString());
break;

Check warning on line 182 in YetAnother.Web/JsonToYamlConverter.cs

View workflow job for this annotation

GitHub Actions / build

Unreachable code detected

}
}

}

private void EmitPropertyNameToYaml(IEmitter emitter, string str, JToken token)
Expand Down Expand Up @@ -185,7 +212,7 @@ private void EmitStringToYaml(IEmitter emitter, string str, JToken token)
}

ScalarStyle style = ScalarStyle.Any;
Console.WriteLine($"path: {token.Path}");
Console.WriteLine($"path: {token?.Path}");

if (str.Length > emitterSettings.BestWidth && str.Contains(' '))
{
Expand Down
28 changes: 25 additions & 3 deletions YetAnother.Web/Pages/Converter.razor
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@

<h1>Json to Yaml Converter</h1>

<span style="color: darkred">@errorMessage</span>

<EditForm EditContext="editContext" OnValidSubmit="Submit">
<DataAnnotationsValidator />
<ValidationSummary />
Expand All @@ -26,9 +28,11 @@




@code {
private EditContext? editContext;
private JsonToYamlConverter Model { get; set; } = new();
private string? errorMessage;

protected override void OnInitialized()
{
Expand All @@ -37,14 +41,32 @@

private void Submit()
{
errorMessage = "";

if (editContext != null && editContext.Validate())
{
var jtoken = Model.ParseJson(Model.JsonString);
Model.YamlString = Model.ConvertToYaml(jtoken);
Logger.LogInformation("Submit called: Form is valid");
try
{
var jtokens = Model.ParseJson(Model.JsonString);
Model.YamlString = Model.ConvertToYaml(jtokens);
Logger.LogInformation("Submit called: Form is valid");
}
catch (JsonException ex)
{
errorMessage = $"Invalid JSON: {ex.Message}";
}
catch (YamlException ex)
{
errorMessage = $"YAML Error: {ex.Message}";
}
catch (Exception ex)
{
errorMessage = $"{ex.GetType().Name}: {ex.Message}";
}
}
else
{
errorMessage = "form is invalid";
Logger.LogInformation("Submit called: Form is INVALID");
}
}
Expand Down

0 comments on commit 3040b39

Please sign in to comment.