/**
* DpDeukYamlProtocol — Deuk YAML (값만) 프로토콜.
* DpDeukJsonProtocol 과 동일한 필드 트리; 루트 직렬화만 YAML.
* See: DeukPack/docs/DEUKPACK_DEUK_JSON_YAML.md
*/
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Text;
using YamlDotNet.RepresentationModel;
using YamlDotNet.Serialization;
namespace DeukPack.Protocol
{
///
/// Deuk YAML protocol: value-only YAML for config/OpenAPI round-trip (TS protocol: 'yaml' 와 같은 계열).
///
public class DpDeukYamlProtocol : DpDeukJsonProtocol
{
public DpDeukYamlProtocol(Stream stream, bool pretty = false, bool includeDeukHeader = true, bool isReadMode = true)
: base(stream, pretty, includeDeukHeader, isReadMode, isReadMode ? ReadYamlRootFromStream(stream) : new Dictionary())
{
}
private static Dictionary ReadYamlRootFromStream(Stream stream)
{
var utf8 = new UTF8Encoding(false);
using (var sr = new StreamReader(stream, utf8, false, 4096, true))
{
var text = sr.ReadToEnd();
if (string.IsNullOrWhiteSpace(text))
return new Dictionary();
return YamlRootToDictionary(text);
}
}
protected override void FlushRootDocument(Stream stream, Dictionary document, bool pretty)
{
var builder = new SerializerBuilder();
if (pretty)
builder = builder.WithIndentedSequences();
var serializer = builder
.ConfigureDefaultValuesHandling(DefaultValuesHandling.OmitNull)
.DisableAliases()
.Build();
var yaml = serializer.Serialize(document);
var bytes = Encoding.UTF8.GetBytes(yaml);
stream.Write(bytes, 0, bytes.Length);
stream.Flush();
}
private static Dictionary YamlRootToDictionary(string yaml)
{
using var reader = new StringReader(yaml);
var ys = new YamlStream();
ys.Load(reader);
if (ys.Documents.Count == 0)
return new Dictionary();
if (ys.Documents[0].RootNode is YamlMappingNode map)
return MappingToDict(map);
return new Dictionary();
}
private static Dictionary MappingToDict(YamlMappingNode map)
{
var d = new Dictionary();
foreach (var child in map.Children)
{
var key = child.Key.ToString();
d[key] = NodeToValue(child.Value);
}
return d;
}
private static object NodeToValue(YamlNode node)
{
switch (node)
{
case YamlMappingNode m:
return MappingToDict(m);
case YamlSequenceNode seq:
{
var list = new List