Skip to content

Commit

Permalink
added method to detect if a yaml fragment is a sequence (#720)
Browse files Browse the repository at this point in the history
  • Loading branch information
mizrael authored Sep 18, 2024
1 parent 7e19a95 commit 1b70d5c
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -198,4 +198,21 @@ public void RoundTripFromYaml(string path)
}

#endregion

#region Is Sequence checks

[TestMethod]
[DataRow(@"_TestData/SchemaV3_0/Examples/Src/App.pa.yaml", false)]
[DataRow(@"_TestData/SchemaV3_0/Examples/Src/Screens/Screen1.pa.yaml", false)]
[DataRow(@"_TestData/SchemaV3_0/Examples/Src/Components/MyHeaderComponent.pa.yaml", false)]
[DataRow(@"_TestData/ValidYaml-CI/With-list-of-controls.pa.yaml", true)]
[DataRow(@"_TestData/InvalidYaml/Dupliacte-Keys.pa.yaml", false)]
public void IsSequenceCheckShouldWorkAsExpected(string path, bool expected)
{
var yaml = File.ReadAllText(path);
var isSequence = PaYamlSerializer.CheckIsSequence(yaml);
isSequence.Should().Be(expected);
}

#endregion
}
40 changes: 40 additions & 0 deletions src/Persistence/PaYaml/Serialization/PaYamlSerializer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -128,5 +128,45 @@ private static void WriteTextWriter<TValue>(TextWriter writer, in TValue? value,
// See: fluentvalidation.net
// See: https://www.youtube.com/watch?v=jblRYDMTtvg
}

/// <summary>
/// checks the input source is a sequence of YAML items.
/// </summary>
/// <param name="yaml">The YAML text to check.</param>
/// <returns></returns>
/// <exception cref="ArgumentNullException"></exception>
public static bool CheckIsSequence(string yaml)
{
_ = yaml ?? throw new ArgumentNullException(nameof(yaml));

using var reader = new StringReader(yaml);
return CheckIsSequence(reader);
}

/// <summary>
/// checks the input source is a sequence of YAML items.
/// </summary>
/// <param name="reader"></param>
/// <returns></returns>
/// <exception cref="ArgumentNullException"></exception>
public static bool CheckIsSequence(StringReader reader)
{
ArgumentNullException.ThrowIfNull(reader);

var builder = new DeserializerBuilder()
.IgnoreUnmatchedProperties()
.WithTypeConverter(new YamlSequenceTesterConverter());
var deserializer = builder.Build();
try
{
var results = deserializer.Deserialize<object[]>(reader);
return results is not null;
}
catch (YamlException)
{
return false;
}
}

#endregion
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

using System.Collections;
using YamlDotNet.Core;
using YamlDotNet.Core.Events;
using YamlDotNet.Serialization;

namespace Microsoft.PowerPlatform.PowerApps.Persistence.PaYaml.Serialization;

/// <summary>
/// custom converter used to test if the input is a sequence of YAML items.
/// </summary>
internal sealed class YamlSequenceTesterConverter : IYamlTypeConverter
{
public bool Accepts(Type type)
{
return type == typeof(IEnumerable) || type.IsSubclassOf(typeof(IEnumerable)) ||
type == typeof(IEnumerable<object>) || type.IsSubclassOf(typeof(IEnumerable<object>)) ||
type == typeof(object[]);
}

public object? ReadYaml(IParser parser, Type type)
{
if (parser.Current is not SequenceStart)
throw new YamlException(parser.Current!.Start, parser.Current.End, $"Expected sequence start but got {parser.Current.GetType().Name}");

while (!parser.Accept<SequenceEnd>(out _))
{
parser.MoveNext();
}

parser.MoveNext();

return Array.Empty<object>();
}

public void WriteYaml(IEmitter emitter, object? value, Type type)
{
throw new NotImplementedException();
}
}

0 comments on commit 1b70d5c

Please # to comment.