feat: add typed production settings contract

This commit is contained in:
codex
2026-08-07 14:23:34 +03:00
parent 9a41d831b4
commit 652515c2ba
2 changed files with 101 additions and 0 deletions
@@ -0,0 +1,63 @@
using System.Globalization;
using System.Xml.Linq;
namespace PRecAnnot.Core;
/// <summary>Typed projection of the release Settings.xml sections consumed by production workflows.</summary>
public sealed record ProductionSettingsContract(
IReadOnlyList<NamedDrawingObject> CopyMissingObjects,
IReadOnlyList<LayerSetupRule> LayerSetup,
string AnnotationLayer,
string AnnotationTextStyle,
string AnnotationLeaderStyle,
string ConnectionPolylineLayer,
string ConnectionTextLayer,
string ConnectionTextStyle,
string ElevationLayer,
string ElevationTextStyle,
string SetLayer,
double? FixedSupportPlusLength,
string? ScriptFolder)
{
public static ProductionSettingsContract Parse(string xml)
{
var root = XElement.Parse(xml, LoadOptions.PreserveWhitespace);
var copy = root.Element("CopyMissingObjects")?.Elements("Object")
.Select(value => new NamedDrawingObject(Required(value, "type"), Required(value, "name")))
.ToArray() ?? Array.Empty<NamedDrawingObject>();
var layers = root.Element("LayersSetup")?.Elements("LayerSetup")
.Select(value => new LayerSetupRule(
Required(value, "filtertype"), Required(value, "filtervalue", allowEmpty: true),
ParseInt(value, "lineweight"), Required(value, "linetype", allowEmpty: true),
Required(value, "color", allowEmpty: true)))
.ToArray() ?? Array.Empty<LayerSetupRule>();
var annotations = root.Element("Annotations");
var connections = root.Element("LinenumberConnections");
var elevations = root.Element("Elevations");
var setLayer = root.Element("SetLayer")?.Attribute("name")?.Value;
if (string.IsNullOrWhiteSpace(setLayer)) throw Invalid("SetLayer.name");
var plusLength = root.Element("PlusLengthNO")?.Attribute("value")?.Value;
double? parsedPlusLength = double.TryParse(plusLength, NumberStyles.Float, CultureInfo.InvariantCulture, out var plus) ? plus : null;
return new(
copy,
layers,
Required(annotations, "layer"),
Required(annotations, "textstyle"),
Required(annotations, "multileaderstyle"),
Required(connections, "polylinelayer"),
Required(connections, "textlayer"),
Required(connections, "textstyle"),
Required(elevations, "layer"),
Required(elevations, "textstyle"),
setLayer,
parsedPlusLength,
root.Element("ScriptFolder")?.Attribute("path")?.Value);
}
private static int? ParseInt(XElement value, string name) => int.TryParse(value.Attribute(name)?.Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var parsed) ? parsed : null;
private static string Required(XElement? value, string name, bool allowEmpty = false) => value?.Attribute(name) is { Value: var result } && (allowEmpty || !string.IsNullOrWhiteSpace(result)) ? result : throw Invalid(name);
private static InvalidDataException Invalid(string field) => new("PRODUCTION_SETTINGS_INVALID:" + field);
}
public sealed record NamedDrawingObject(string Type, string Name);
public sealed record LayerSetupRule(string FilterType, string FilterValue, int? LineWeight, string LineType, string Color);