Skip to content

Commit

Permalink
Add anchor/alias support in JsonEventEmitter
Browse files Browse the repository at this point in the history
  • Loading branch information
am11 committed May 9, 2020
1 parent 49bda13 commit 536d341
Show file tree
Hide file tree
Showing 8 changed files with 74 additions and 14 deletions.
26 changes: 23 additions & 3 deletions YamlDotNet.Test/Serialization/SerializationTests.cs
Expand Up @@ -27,19 +27,17 @@
using System.ComponentModel;
using System.Drawing;
using System.Dynamic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Globalization;
using System.Reflection;
using System.Text.RegularExpressions;
using Xunit;
using YamlDotNet.Core;
using YamlDotNet.Core.Events;
using YamlDotNet.RepresentationModel;
using YamlDotNet.Serialization;
using YamlDotNet.Serialization.NamingConventions;
using YamlDotNet.Serialization.ObjectFactories;
using YamlDotNet.Serialization.TypeInspectors;

namespace YamlDotNet.Test.Serialization
{
Expand Down Expand Up @@ -810,6 +808,28 @@ public void SerializationOfLongKeysWorksInJson()
writer.ToString().Should().NotContain("?");
}


[Fact]
public void SerializationOfAnchorWorksInJson()
{
var yamlString = @"
x: &anchor1
z:
v: 1
y:
k: *anchor1";

var deserializer = new DeserializerBuilder().Build();
var yamlObject = deserializer.Deserialize(new StringReader(yamlString));

var serializer = new SerializerBuilder()
.JsonCompatible()
.Build();

serializer.Serialize(yamlObject).Trim().Should()
.BeEquivalentTo(@"{""x"": {""z"": {""v"": ""1""}}, ""y"": {""k"": {""z"": {""v"": ""1""}}}}");
}

[Fact]
// Todo: this is actually roundtrip
public void DeserializationOfDefaultsWorkInJson()
Expand Down
4 changes: 3 additions & 1 deletion YamlDotNet/Core/Emitter.cs
Expand Up @@ -45,6 +45,7 @@ public class Emitter : IEmitter

private readonly int maxSimpleKeyLength;
private readonly bool isCanonical;
private readonly bool skipAnchorName;
private readonly int bestIndent;
private readonly int bestWidth;
private EmitterState state;
Expand Down Expand Up @@ -140,6 +141,7 @@ public Emitter(TextWriter output, EmitterSettings settings)
this.bestWidth = settings.BestWidth;
this.isCanonical = settings.IsCanonical;
this.maxSimpleKeyLength = settings.MaxSimpleKeyLength;
this.skipAnchorName = settings.SkipAnchorName;

this.output = output;
this.outputUsesUnicodeEncoding = IsUnicode(output.Encoding);
Expand Down Expand Up @@ -1375,7 +1377,7 @@ private void EmitMappingStart(ParsingEvent evt)

private void ProcessAnchor()
{
if (anchorData.anchor != null)
if (anchorData.anchor != null && !skipAnchorName)
{
WriteIndicator(anchorData.isAlias ? "*" : "&", true, false, false);
WriteAnchor(anchorData.anchor);
Expand Down
38 changes: 36 additions & 2 deletions YamlDotNet/Core/EmitterSettings.cs
@@ -1,4 +1,25 @@
using System;
// This file is part of YamlDotNet - A .NET library for YAML.
// Copyright (c) Antoine Aubry and contributors

// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
// of the Software, and to permit persons to whom the Software is furnished to do
// so, subject to the following conditions:

// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

using System;

namespace YamlDotNet.Core
{
Expand All @@ -19,6 +40,11 @@ public sealed class EmitterSettings
/// </summary>
public bool IsCanonical { get; } = false;

/// <summary>
/// If true, write output without anchor names.
/// </summary>
public bool SkipAnchorName { get; private set; }

/// <summary>
/// The maximum allowed length for simple keys.
/// </summary>
Expand All @@ -33,7 +59,7 @@ public EmitterSettings()
{
}

public EmitterSettings(int bestIndent, int bestWidth, bool isCanonical, int maxSimpleKeyLength)
public EmitterSettings(int bestIndent, int bestWidth, bool isCanonical, int maxSimpleKeyLength, bool skipAnchorName = false)
{
if (bestIndent < 2 || bestIndent > 9)
{
Expand All @@ -54,6 +80,7 @@ public EmitterSettings(int bestIndent, int bestWidth, bool isCanonical, int maxS
BestWidth = bestWidth;
IsCanonical = isCanonical;
MaxSimpleKeyLength = maxSimpleKeyLength;
SkipAnchorName = skipAnchorName;
}

public EmitterSettings WithBestIndent(int bestIndent)
Expand Down Expand Up @@ -95,5 +122,12 @@ public EmitterSettings Canonical()
MaxSimpleKeyLength
);
}

public EmitterSettings WithoutAnchorName()
{
SkipAnchorName = true;
return this;
}

}
}
2 changes: 1 addition & 1 deletion YamlDotNet/Serialization/EventEmitters/JsonEventEmitter.cs
Expand Up @@ -35,7 +35,7 @@ public JsonEventEmitter(IEventEmitter nextEmitter)

public override void Emit(AliasEventInfo eventInfo, IEmitter emitter)
{
throw new NotSupportedException("Aliases are not supported in JSON");
eventInfo.NeedsExpansion = true;
}

public override void Emit(ScalarEventInfo eventInfo, IEmitter emitter)
Expand Down
3 changes: 2 additions & 1 deletion YamlDotNet/Serialization/EventInfo.cs
Expand Up @@ -44,6 +44,7 @@ public AliasEventInfo(IObjectDescriptor source, string alias)
}

public string Alias { get; }
public bool NeedsExpansion { get; set; }
}

public class ObjectEventInfo : EventInfo
Expand Down Expand Up @@ -109,4 +110,4 @@ public SequenceEndEventInfo(IObjectDescriptor source)
{
}
}
}
}
Expand Up @@ -45,8 +45,9 @@ public override bool Enter(IObjectDescriptor value, IEmitter context)
var alias = aliasProvider.GetAlias(value.Value);
if (alias != null && !emittedAliases.Add(alias))
{
eventEmitter.Emit(new AliasEventInfo(value, alias), context);
return false;
var aliasEventInfo = new AliasEventInfo(value, alias);
eventEmitter.Emit(aliasEventInfo, context);
return aliasEventInfo.NeedsExpansion;
}
}
return base.Enter(value, context);
Expand Down Expand Up @@ -74,4 +75,4 @@ public override void VisitScalar(IObjectDescriptor scalar, IEmitter context)
eventEmitter.Emit(scalarInfo, context);
}
}
}
}
8 changes: 5 additions & 3 deletions YamlDotNet/Serialization/SerializerBuilder.cs
Expand Up @@ -286,7 +286,9 @@ public SerializerBuilder ConfigureDefaultValuesHandling(DefaultValuesHandling co
/// </summary>
public SerializerBuilder JsonCompatible()
{
this.emitterSettings = this.emitterSettings.WithMaxSimpleKeyLength(int.MaxValue);
this.emitterSettings = this.emitterSettings
.WithMaxSimpleKeyLength(int.MaxValue)
.WithoutAnchorName();

return this
.WithTypeConverter(new GuidConverter(true), w => w.InsteadOf<GuidConverter>())
Expand Down Expand Up @@ -554,7 +556,7 @@ public void SerializeValue(IEmitter emitter, object? value, Type? type)
var preProcessingPhaseObjectGraphVisitors = preProcessingPhaseObjectGraphVisitorFactories.BuildComponentList(typeConverters);
foreach (var visitor in preProcessingPhaseObjectGraphVisitors)
{
traversalStrategy.Traverse(graph, visitor, null);
traversalStrategy.Traverse(graph, visitor, null!);
}

void nestedObjectSerializer(object? v, Type? t) => SerializeValue(emitter, v, t);
Expand All @@ -568,4 +570,4 @@ public void SerializeValue(IEmitter emitter, object? value, Type? type)
}
}
}
}
}
File renamed without changes.

0 comments on commit 536d341

Please sign in to comment.