From f00bde7e24008bd4f0f4a3386f40008eab47eb6a Mon Sep 17 00:00:00 2001 From: "christopher.bell@i3-corps.com" Date: Thu, 17 Jul 2025 10:14:44 -0500 Subject: [PATCH] Adding per object validation --- SessionZero.SzfCli/Program.cs | 35 ++++++++++------ SessionZero.SzfLib/Helpers/SzfError.cs | 18 +++++++++ SessionZero.SzfLib/Helpers/SzfHelper.cs | 12 ++++++ SessionZero.SzfLib/Objects/ISzfObject.cs | 7 +++- SessionZero.SzfLib/Objects/SzfCharacter.cs | 6 +++ .../Objects/SzfCharacterTemplate.cs | 6 +++ SessionZero.SzfLib/Objects/SzfDataset.cs | 20 +++++++++- SessionZero.SzfLib/Objects/SzfObject.cs | 6 ++- SessionZero.SzfLib/Parser/SzfField.cs | 13 ++++++ SessionZero.SzfLib/Parser/SzfFieldType.cs | 13 ++++++ SessionZero.SzfLib/Parser/SzfParser.cs | 40 +++++-------------- SessionZero.SzfLib/Parser/SzfSection.cs | 8 ++++ 12 files changed, 137 insertions(+), 47 deletions(-) create mode 100644 SessionZero.SzfLib/Helpers/SzfError.cs create mode 100644 SessionZero.SzfLib/Parser/SzfField.cs create mode 100644 SessionZero.SzfLib/Parser/SzfFieldType.cs create mode 100644 SessionZero.SzfLib/Parser/SzfSection.cs diff --git a/SessionZero.SzfCli/Program.cs b/SessionZero.SzfCli/Program.cs index 250be58..b79db27 100644 --- a/SessionZero.SzfCli/Program.cs +++ b/SessionZero.SzfCli/Program.cs @@ -1,6 +1,7 @@ using Spectre.Console; using SessionZero.SzfLib.Parser; using System.IO; +using SessionZero.SzfLib.Helpers; void PrintSection(dynamic section, int indent = 0) { @@ -55,19 +56,27 @@ if (!File.Exists(filePath)) string szfContent = File.ReadAllText(filePath); var parser = new SzfParser(); -var szfObject = parser.Parse(szfContent); - -if (szfObject == null) +try { - AnsiConsole.MarkupLine("[red]Failed to parse SZF file.[/]"); - return; + var szfObject = parser.Parse(szfContent); + + if (szfObject == null) + { + AnsiConsole.MarkupLine("[red]Failed to parse SZF file.[/]"); + return; + } + + AnsiConsole.MarkupLine($"[bold]SZF Type:[/] {szfObject.SzfType}"); + AnsiConsole.MarkupLine($"[bold]SZF Version:[/] {szfObject.SzfVersion}"); + AnsiConsole.MarkupLine($"[bold]Number of Sections:[/] {szfObject.Sections.Count}"); + + foreach (var section in szfObject.Sections) + { + PrintSection(section); + } +} +catch (SzfError ex) +{ + Console.WriteLine($"Szf Validation Error: {ex.Message}"); } -AnsiConsole.MarkupLine($"[bold]SZF Type:[/] {szfObject.SzfType}"); -AnsiConsole.MarkupLine($"[bold]SZF Version:[/] {szfObject.SzfVersion}"); -AnsiConsole.MarkupLine($"[bold]Number of Sections:[/] {szfObject.Sections.Count}"); - -foreach (var section in szfObject.Sections) -{ - PrintSection(section); -} \ No newline at end of file diff --git a/SessionZero.SzfLib/Helpers/SzfError.cs b/SessionZero.SzfLib/Helpers/SzfError.cs new file mode 100644 index 0000000..c9c68b5 --- /dev/null +++ b/SessionZero.SzfLib/Helpers/SzfError.cs @@ -0,0 +1,18 @@ +namespace SessionZero.SzfLib.Helpers; + +public class SzfError : Exception +{ + public bool IsValid { get; set; } = true; + public string Message { get; set; } = string.Empty; + + public void AddError(string message) + { + Message += message + "\r\n"; + IsValid = false; + } + + public override string ToString() + { + return $"Valid: {IsValid}, Message: {Message}"; + } +} \ No newline at end of file diff --git a/SessionZero.SzfLib/Helpers/SzfHelper.cs b/SessionZero.SzfLib/Helpers/SzfHelper.cs index fb835ac..ee33f19 100644 --- a/SessionZero.SzfLib/Helpers/SzfHelper.cs +++ b/SessionZero.SzfLib/Helpers/SzfHelper.cs @@ -16,4 +16,16 @@ public static class SzfHelper return obj.IsAbstract || obj.IsInterface ? null : obj; } + + public static SzfError BasicSzfValidation(ISzfObject obj) + { + SzfError result = new SzfError(); + + var metadataSection = obj.Sections.FirstOrDefault(s => s.Name == "Metadata"); + if (metadataSection is null) result.AddError("No metadata section found"); + + if (obj.GetMetadataField("Name") == string.Empty) result.AddError("No metadata field name found"); + + return result; + } } \ No newline at end of file diff --git a/SessionZero.SzfLib/Objects/ISzfObject.cs b/SessionZero.SzfLib/Objects/ISzfObject.cs index e557dd9..77cb7a5 100644 --- a/SessionZero.SzfLib/Objects/ISzfObject.cs +++ b/SessionZero.SzfLib/Objects/ISzfObject.cs @@ -1,3 +1,4 @@ +using SessionZero.SzfLib.Helpers; using SessionZero.SzfLib.Parser; namespace SessionZero.SzfLib.Objects; @@ -12,5 +13,9 @@ public interface ISzfObject public string GetFieldValue(string sectionName, string fieldName); public string FindFieldValueInSection(SzfSection section, string[] path, int depth, string fieldName); - public ISzfObject? Parse(); + /// + /// + /// + /// + public SzfError Validate(); } \ No newline at end of file diff --git a/SessionZero.SzfLib/Objects/SzfCharacter.cs b/SessionZero.SzfLib/Objects/SzfCharacter.cs index 3203507..d1603b0 100644 --- a/SessionZero.SzfLib/Objects/SzfCharacter.cs +++ b/SessionZero.SzfLib/Objects/SzfCharacter.cs @@ -1,7 +1,13 @@ +using SessionZero.SzfLib.Helpers; + namespace SessionZero.SzfLib.Objects; [SzfObject("character")] public class SzfCharacter : SzfObject, ISzfCharacter { public override string SzfType { get; set; } = "character"; + public override SzfError Validate() + { + throw new NotImplementedException(); + } } \ No newline at end of file diff --git a/SessionZero.SzfLib/Objects/SzfCharacterTemplate.cs b/SessionZero.SzfLib/Objects/SzfCharacterTemplate.cs index 2f14878..18407eb 100644 --- a/SessionZero.SzfLib/Objects/SzfCharacterTemplate.cs +++ b/SessionZero.SzfLib/Objects/SzfCharacterTemplate.cs @@ -1,7 +1,13 @@ +using SessionZero.SzfLib.Helpers; + namespace SessionZero.SzfLib.Objects; [SzfObject("character_template")] public class SzfCharacterTemplate : SzfObject, ISzfCharacterTemplate { public override string SzfType { get; set; } = "character_template"; + public override SzfError Validate() + { + throw new NotImplementedException(); + } } \ No newline at end of file diff --git a/SessionZero.SzfLib/Objects/SzfDataset.cs b/SessionZero.SzfLib/Objects/SzfDataset.cs index 414c9a5..df2d3fb 100644 --- a/SessionZero.SzfLib/Objects/SzfDataset.cs +++ b/SessionZero.SzfLib/Objects/SzfDataset.cs @@ -1,7 +1,25 @@ +using SessionZero.SzfLib.Helpers; +using SessionZero.SzfLib.Parser; + namespace SessionZero.SzfLib.Objects; [SzfObject("dataset")] public class SzfDataset : SzfObject, ISzfDataset { public override string SzfType { get; set; } = "dataset"; -} \ No newline at end of file + + + public override SzfError Validate() + { + var result = SzfHelper.BasicSzfValidation(this); + + if (GetMetadataField("Type") == string.Empty) result.AddError("Metadata field `Type` is missing or empty"); + + foreach (var entry in Sections.Where(entry => GetFieldValue(entry.Name, "Name") == string.Empty)) + { + result.AddError($"Entry {entry.Name}'s `Name` field is missing or empty"); + } + + return result; + } +} diff --git a/SessionZero.SzfLib/Objects/SzfObject.cs b/SessionZero.SzfLib/Objects/SzfObject.cs index 92edb7b..99a3249 100644 --- a/SessionZero.SzfLib/Objects/SzfObject.cs +++ b/SessionZero.SzfLib/Objects/SzfObject.cs @@ -1,3 +1,4 @@ +using SessionZero.SzfLib.Helpers; using SessionZero.SzfLib.Parser; namespace SessionZero.SzfLib.Objects; @@ -13,9 +14,10 @@ public abstract class SzfObject : ISzfObject /// Handles specific parsing logic for the SzfObject that overrides this method. /// /// - public virtual ISzfObject? Parse() + public virtual SzfError Validate() { - return this; + var result = SzfHelper.BasicSzfValidation(this); + return result; } /// diff --git a/SessionZero.SzfLib/Parser/SzfField.cs b/SessionZero.SzfLib/Parser/SzfField.cs new file mode 100644 index 0000000..3f0a5ca --- /dev/null +++ b/SessionZero.SzfLib/Parser/SzfField.cs @@ -0,0 +1,13 @@ +namespace SessionZero.SzfLib.Parser; + +public class SzfField(string name, SzfFieldType type) +{ + public string Name { get; set; } = name; + public SzfFieldType SzfType { get; set; } = type; + public string? Value { get; set; } + + public bool Validate() + { + throw new NotImplementedException(); + } +} \ No newline at end of file diff --git a/SessionZero.SzfLib/Parser/SzfFieldType.cs b/SessionZero.SzfLib/Parser/SzfFieldType.cs new file mode 100644 index 0000000..4f69cfe --- /dev/null +++ b/SessionZero.SzfLib/Parser/SzfFieldType.cs @@ -0,0 +1,13 @@ +namespace SessionZero.SzfLib.Parser; + +public enum SzfFieldType +{ + Text, + TextField, + Number, + Bool, + Calculated, + System, + EntryReference, + EntryReferenceList, +} \ No newline at end of file diff --git a/SessionZero.SzfLib/Parser/SzfParser.cs b/SessionZero.SzfLib/Parser/SzfParser.cs index c54d39b..3743371 100644 --- a/SessionZero.SzfLib/Parser/SzfParser.cs +++ b/SessionZero.SzfLib/Parser/SzfParser.cs @@ -7,12 +7,15 @@ namespace SessionZero.SzfLib.Parser; public class SzfParser : ISzfParser { /// - /// Parses the given SZF content and returns the corresponding ISzfObject. + /// Tries to parse an ISzfObject /// /// /// + /// public ISzfObject? Parse(string szfContent) { + SzfError result = new(); + var lines = szfContent.Split(new[] { '\n', '\r' }, StringSplitOptions.RemoveEmptyEntries); string szfObjectTypeName = string.Empty; @@ -72,11 +75,15 @@ public class SzfParser : ISzfParser { szfObject.Sections.Add(section); } + + result = szfObject.Validate(); - return szfObject.Parse() ?? szfObject; + if (result.IsValid) return szfObject; + + Console.WriteLine(result.Message); } - return null; + throw result; } public ISzfObject? Parse(ISzfFile file) @@ -143,31 +150,4 @@ public class SzfParser : ISzfParser } -} - -public class SzfSection(string name) -{ - public string Name { get; set; } = name; - public Dictionary Fields { get; set; } = new(); - public Dictionary Subsections { get; set; } = new(); -} - - -public class SzfField(string name, SzfFieldType type) -{ - public string Name { get; set; } = name; - public SzfFieldType SzfType { get; set; } = type; - public string? Value { get; set; } -} - -public enum SzfFieldType -{ - Text, - TextField, - Number, - Bool, - Calculated, - System, - EntryReference, - EntryReferenceList, } \ No newline at end of file diff --git a/SessionZero.SzfLib/Parser/SzfSection.cs b/SessionZero.SzfLib/Parser/SzfSection.cs new file mode 100644 index 0000000..662c59f --- /dev/null +++ b/SessionZero.SzfLib/Parser/SzfSection.cs @@ -0,0 +1,8 @@ +namespace SessionZero.SzfLib.Parser; + +public class SzfSection(string name) +{ + public string Name { get; set; } = name; + public Dictionary Fields { get; set; } = new(); + public Dictionary Subsections { get; set; } = new(); +} \ No newline at end of file