Seperation of szf generator. Updated test page
This commit is contained in:
parent
22cce4257d
commit
678c10a872
132
5e_template.szf
Normal file
132
5e_template.szf
Normal file
@ -0,0 +1,132 @@
|
||||
!type: character_template
|
||||
!schema: 1.0.0
|
||||
|
||||
[Metadata]
|
||||
Name (text) = D&D 5e Character Sheet
|
||||
Version (text) = 1.0.0
|
||||
GUID (text) = 5e0c7a12-d4b9-4f3e-9c87-a1b2c3d4e5f6
|
||||
Description (text-field) = A comprehensive character sheet template for Dungeons & Dragons 5th Edition, covering core stats, skills, combat, and general information.
|
||||
Author (text) = AI Assistant
|
||||
GameSystem (text) = Dungeons & Dragons 5th Edition
|
||||
|
||||
[Required Datasets]
|
||||
DnD5eRaces (dataset-reference) = D&D 5e Races|e1a2b3c4-d5e6-7f8a-9b0c-1d2e3f4a5b6c|1.0.0
|
||||
DnD5eClasses (dataset-reference) = D&D 5e Classes|f1e2d3c4-b5a6-7980-1234-56789abcdef0|1.0.0
|
||||
DnD5eSpells (dataset-reference) = D&D 5e Spells|a1b2c3d4-e5f6-7890-1234-567890abcdef|1.0.0
|
||||
DnD5eEquipment (dataset-reference) = D&D 5e Equipment|b1c2d3e4-f5a6-7890-1234-567890fedcba|1.0.0
|
||||
|
||||
[Section: Character Information]
|
||||
CharacterName (text) =
|
||||
PlayerName (text) =
|
||||
Race (dataset-reference) = DnD5eRaces
|
||||
Class (dataset-reference) = DnD5eClasses
|
||||
Level (number) = 1
|
||||
Background (text) =
|
||||
Alignment (text) =
|
||||
ExperiencePoints (number) = 0
|
||||
ProficiencyBonus (calculated) = 2 + floor((Level - 1) / 4)
|
||||
|
||||
[Section: Ability Scores]
|
||||
Strength (number) = 10
|
||||
Dexterity (number) = 10
|
||||
Constitution (number) = 10
|
||||
Intelligence (number) = 10
|
||||
Wisdom (number) = 10
|
||||
Charisma (number) = 10
|
||||
|
||||
[Section.Ability Scores.Modifiers]
|
||||
StrengthMod (calculated) = floor((Strength - 10) / 2)
|
||||
DexterityMod (calculated) = floor((Dexterity - 10) / 2)
|
||||
ConstitutionMod (calculated) = floor((Constitution - 10) / 2)
|
||||
IntelligenceMod (calculated) = floor((Intelligence - 10) / 2)
|
||||
WisdomMod (calculated) = floor((Wisdom - 10) / 2)
|
||||
CharismaMod (calculated) = floor((Charisma - 10) / 2)
|
||||
|
||||
[Section: Saving Throws]
|
||||
StrengthSave (number) = 0
|
||||
DexteritySave (number) = 0
|
||||
ConstitutionSave (number) = 0
|
||||
IntelligenceSave (number) = 0
|
||||
WisdomSave (number) = 0
|
||||
CharismaSave (number) = 0
|
||||
|
||||
[Section: Skills]
|
||||
Acrobatics (number) = 0
|
||||
AnimalHandling (number) = 0
|
||||
Arcana (number) = 0
|
||||
Athletics (number) = 0
|
||||
Deception (number) = 0
|
||||
History (number) = 0
|
||||
Insight (number) = 0
|
||||
Intimidation (number) = 0
|
||||
Investigation (number) = 0
|
||||
Medicine (number) = 0
|
||||
Nature (number) = 0
|
||||
Perception (number) = 0
|
||||
Performance (number) = 0
|
||||
Persuasion (number) = 0
|
||||
Religion (number) = 0
|
||||
SleightOfHand (number) = 0
|
||||
Stealth (number) = 0
|
||||
Survival (number) = 0
|
||||
|
||||
[Section: Combat]
|
||||
ArmorClass (number) = 0
|
||||
Initiative (calculated) = DexterityMod
|
||||
Speed (number) = 30
|
||||
HitPointsMax (number) = 0
|
||||
HitPointsCurrent (number) = 0
|
||||
TemporaryHitPoints (number) = 0
|
||||
HitDice (text) =
|
||||
DeathSavesSuccess (number) = 0
|
||||
DeathSavesFailure (number) = 0
|
||||
|
||||
[Section: Senses]
|
||||
PassivePerception (calculated) = 10 + Perception
|
||||
Darkvision (text) =
|
||||
|
||||
[Section: Feats & Traits]
|
||||
Feats (text-field) =
|
||||
RacialTraits (text-field) =
|
||||
ClassFeatures (text-field) =
|
||||
OtherProficienciesAndLanguages (text-field) =
|
||||
|
||||
[Section: Equipment]
|
||||
CopperPieces (number) = 0
|
||||
SilverPieces (number) = 0
|
||||
ElectrumPieces (number) = 0
|
||||
GoldPieces (number) = 0
|
||||
PlatinumPieces (number) = 0
|
||||
Inventory (text-field) =
|
||||
|
||||
[Section: Spellcasting]
|
||||
SpellcastingAbility (text) =
|
||||
SpellSaveDC (number) = 0
|
||||
SpellAttackBonus (number) = 0
|
||||
|
||||
[Section.Spellcasting.Cantrips]
|
||||
Cantrips (dataset-type-multiple) = DnD5eSpells
|
||||
|
||||
[Section.Spellcasting.Level1Spells]
|
||||
Level1SlotsTotal (number) = 0
|
||||
Level1SlotsUsed (number) = 0
|
||||
Level1Spells (dataset-type-multiple) = DnD5eSpells
|
||||
|
||||
[Section.Spellcasting.Level2Spells]
|
||||
Level2SlotsTotal (number) = 0
|
||||
Level2SlotsUsed (number) = 0
|
||||
Level2Spells (dataset-type-multiple) = DnD5eSpells
|
||||
|
||||
[Section.Spellcasting.Level3Spells]
|
||||
Level3SlotsTotal (number) = 0
|
||||
Level3SlotsUsed (number) = 0
|
||||
Level3Spells (dataset-type-multiple) = DnD5eSpells
|
||||
|
||||
[Section: Character Details]
|
||||
PersonalityTraits (text-field) =
|
||||
Ideals (text-field) =
|
||||
Bonds (text-field) =
|
||||
Flaws (text-field) =
|
||||
Backstory (text-field) =
|
||||
AlliesAndOrganizations (text-field) =
|
||||
AdditionalNotes (text-field) =
|
@ -1,4 +1,3 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
@ -9,7 +8,7 @@ public class CharacterTemplate : SzfObject
|
||||
{
|
||||
public string GameSystem { get; set; } = string.Empty;
|
||||
public List<RequiredDatasetReference> RequiredDatasets { get; set; } = new();
|
||||
public List<TemplateSection> Sections { get; set; } = new(); // Top-level sections
|
||||
public List<TemplateSection> Sections { get; set; } = new();
|
||||
|
||||
public override SzfObjectType ObjectType => SzfObjectType.CharacterTemplate;
|
||||
|
||||
@ -23,105 +22,81 @@ public class CharacterTemplate : SzfObject
|
||||
|
||||
public override void ParseSections(List<SzfSection> sections)
|
||||
{
|
||||
// Parse "Required Datasets" section
|
||||
// Parse [Required Datasets] section
|
||||
var requiredDatasetsSection =
|
||||
sections.FirstOrDefault(s => s.Name.Equals("Required Datasets", StringComparison.OrdinalIgnoreCase));
|
||||
if (requiredDatasetsSection != null)
|
||||
{
|
||||
foreach (var field in requiredDatasetsSection.Fields)
|
||||
{
|
||||
var datasetReference = DatasetReference.Parse(field.Value?.ToString() ?? string.Empty);
|
||||
if (datasetReference != null)
|
||||
var reference = DatasetReference.Parse(field.Value?.ToString() ?? string.Empty);
|
||||
if (reference != null)
|
||||
{
|
||||
RequiredDatasets.Add(new RequiredDatasetReference
|
||||
{
|
||||
Alias = field.Name,
|
||||
Reference = datasetReference
|
||||
Reference = reference
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Parse and build the hierarchical template sections
|
||||
// Use a map to quickly find existing sections by their full path for nesting
|
||||
var sectionPathMap = new Dictionary<string, TemplateSection>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
// Parse [Section: ...] and [Section....] sections
|
||||
foreach (var szfSection in sections)
|
||||
{
|
||||
// Only process sections that start with "Section:"
|
||||
if (!szfSection.Name.StartsWith("Section:", StringComparison.OrdinalIgnoreCase)) continue;
|
||||
|
||||
// Normalize the section name (e.g., "Section:Ability Scores.Modifiers" to "Ability Scores.Modifiers")
|
||||
var rawSectionPath = szfSection.Name.Substring("Section:".Length).Trim();
|
||||
var nameParts = rawSectionPath.Split('.');
|
||||
|
||||
TemplateSection? currentParentSection = null;
|
||||
List<TemplateSection> currentSectionList = Sections; // Start from the top-level Sections list
|
||||
|
||||
string accumulatedPath = "Section"; // Used for dictionary key to ensure uniqueness and hierarchy
|
||||
|
||||
for (int i = 0; i < nameParts.Length; i++)
|
||||
if (szfSection.Name.StartsWith("Section:", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var sectionNamePart = nameParts[i];
|
||||
accumulatedPath += "." + sectionNamePart; // Build the full path for the map key
|
||||
|
||||
TemplateSection? targetSection = null;
|
||||
|
||||
// Check if this specific section (at this level of hierarchy) already exists
|
||||
if (sectionPathMap.TryGetValue(accumulatedPath, out var existingSection))
|
||||
var templateSection = new TemplateSection
|
||||
{
|
||||
targetSection = existingSection;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Create a new section if it doesn't exist
|
||||
var newSection = new TemplateSection { Name = sectionNamePart };
|
||||
sectionPathMap[accumulatedPath] = newSection;
|
||||
Name = szfSection.Name.Replace("Section:", "").Trim()
|
||||
};
|
||||
|
||||
if (currentParentSection == null)
|
||||
{
|
||||
// This is a top-level section
|
||||
currentSectionList.Add(newSection);
|
||||
}
|
||||
else
|
||||
{
|
||||
// This is a subsection of the current parent
|
||||
currentParentSection.Subsections.Add(newSection);
|
||||
}
|
||||
|
||||
targetSection = newSection;
|
||||
}
|
||||
|
||||
currentParentSection = targetSection; // Move down the hierarchy
|
||||
currentSectionList =
|
||||
targetSection.Subsections; // Next iteration will look in subsections of this section
|
||||
}
|
||||
|
||||
// Once we've traversed/created the full path, currentParentSection points to the innermost section.
|
||||
// Now populate its fields from the SzfSection.
|
||||
if (currentParentSection != null)
|
||||
{
|
||||
foreach (var field in szfSection.Fields)
|
||||
{
|
||||
currentParentSection.Fields.Add(ConvertToTemplateField(field));
|
||||
}
|
||||
}
|
||||
}
|
||||
templateSection.Fields.Add(ConvertToTemplateField(field));
|
||||
}
|
||||
|
||||
Sections.Add(templateSection);
|
||||
}
|
||||
else if (szfSection.Name.StartsWith("Section.", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
// Handle subsections by finding their parent
|
||||
var parts = szfSection.Name.Split('.');
|
||||
if (parts.Length >= 2)
|
||||
{
|
||||
var parentSectionName = parts[0] + ":" + parts[1].Trim(); // Reconstruct parent name
|
||||
var parentSection = Sections.FirstOrDefault(s =>
|
||||
s.Name.Equals(parentSectionName.Replace("Section:", "").Trim(),
|
||||
StringComparison.OrdinalIgnoreCase));
|
||||
if (parentSection != null)
|
||||
{
|
||||
var subSection = new TemplateSection
|
||||
{
|
||||
Name = string.Join(".", parts.Skip(2)).Trim() // Name for the subsection
|
||||
};
|
||||
|
||||
foreach (var field in szfSection.Fields)
|
||||
{
|
||||
subSection.Fields.Add(ConvertToTemplateField(field));
|
||||
}
|
||||
|
||||
parentSection.Subsections.Add(subSection);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private TemplateField ConvertToTemplateField(SzfField szfField)
|
||||
{
|
||||
return new TemplateField
|
||||
{
|
||||
Name = szfField.Name,
|
||||
Type = ParseDatasetFieldType(szfField.Type), // Reusing DatasetFieldType for consistency
|
||||
Value = szfField.Value,
|
||||
Type = ParseDatasetFieldType(szfField.Type),
|
||||
Value = szfField.Value
|
||||
};
|
||||
}
|
||||
|
||||
// Helper method to parse DatasetFieldType, can be shared or defined here.
|
||||
// Copying from Dataset.cs for now, consider a common utility.
|
||||
private DatasetFieldType ParseDatasetFieldType(string typeString)
|
||||
{
|
||||
return typeString.ToLower() switch
|
||||
@ -130,26 +105,86 @@ public class CharacterTemplate : SzfObject
|
||||
"text-field" => DatasetFieldType.TextField,
|
||||
"number" => DatasetFieldType.Number,
|
||||
"bool" => DatasetFieldType.Boolean,
|
||||
"group" => DatasetFieldType.Group,
|
||||
"calculated" => DatasetFieldType.Calculated,
|
||||
"system" => DatasetFieldType.System,
|
||||
"dataset-reference" => DatasetFieldType.DatasetReference,
|
||||
"dataset-type" => DatasetFieldType.DatasetType,
|
||||
"dataset-reference-multiple" => DatasetFieldType.DatasetReferenceMultiple,
|
||||
"dataset-type-multiple" => DatasetFieldType.DatasetTypeMultiple,
|
||||
_ => DatasetFieldType.Text
|
||||
"group" => DatasetFieldType.Group,
|
||||
_ => DatasetFieldType.Text // Default to text if unknown
|
||||
};
|
||||
}
|
||||
|
||||
public override void GenerateMetadata(SzfFieldWriter writer)
|
||||
{
|
||||
// Call base to ensure common metadata is generated first if base had any specific generation logic
|
||||
base.GenerateMetadata(writer);
|
||||
|
||||
writer.WriteField("GameSystem", "text", GameSystem);
|
||||
}
|
||||
|
||||
public override void GenerateContent(SzfFieldWriter writer)
|
||||
{
|
||||
// Generate [Required Datasets] section
|
||||
if (RequiredDatasets.Any() || writer.Options.IncludeEmptySections)
|
||||
{
|
||||
writer.AppendSectionHeader("Required Datasets");
|
||||
foreach (var reqDataset in RequiredDatasets)
|
||||
{
|
||||
writer.WriteField(reqDataset.Alias, "dataset-reference", reqDataset.Reference?.ToString());
|
||||
}
|
||||
|
||||
writer.AppendLine();
|
||||
}
|
||||
|
||||
// Generate Template Sections
|
||||
foreach (var section in Sections)
|
||||
{
|
||||
GenerateTemplateSection(writer, section, "Section");
|
||||
writer.AppendLine();
|
||||
}
|
||||
}
|
||||
|
||||
private void GenerateTemplateSection(SzfFieldWriter writer, TemplateSection section, string parentPath)
|
||||
{
|
||||
var currentPath = $"{parentPath}: {section.Name}";
|
||||
writer.AppendSectionHeader(currentPath);
|
||||
|
||||
foreach (var field in section.Fields)
|
||||
{
|
||||
writer.WriteField(field.Name, field.Type, field.Value);
|
||||
}
|
||||
|
||||
foreach (var subSection in section.Subsections)
|
||||
{
|
||||
GenerateTemplateSubSection(writer, subSection, $"Section.{section.Name}");
|
||||
}
|
||||
}
|
||||
|
||||
private void GenerateTemplateSubSection(SzfFieldWriter writer, TemplateSection subSection, string parentPath)
|
||||
{
|
||||
var currentPath = $"{parentPath}.{subSection.Name}";
|
||||
writer.AppendSectionHeader(currentPath);
|
||||
|
||||
foreach (var field in subSection.Fields)
|
||||
{
|
||||
writer.WriteField(field.Name, field.Type, field.Value);
|
||||
}
|
||||
|
||||
foreach (var nestedSubSection in subSection.Subsections)
|
||||
{
|
||||
// Handle deeper nesting if needed, recursively calling this method
|
||||
GenerateTemplateSubSection(writer, nestedSubSection, currentPath);
|
||||
}
|
||||
}
|
||||
|
||||
public override SzfValidationResult Validate()
|
||||
{
|
||||
var result = base.Validate();
|
||||
var result = base.Validate(); // Run base validation first
|
||||
|
||||
// if (string.IsNullOrWhiteSpace(GameSystem))
|
||||
// result.AddError("GameSystem is required for CharacterTemplate");
|
||||
|
||||
// Further validation for required datasets and template sections can be added here
|
||||
// e.g., checking for duplicate section names or missing required fields.
|
||||
if (string.IsNullOrWhiteSpace(GameSystem))
|
||||
result.AddError("GameSystem is required for CharacterTemplate");
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -165,7 +200,7 @@ public class TemplateSection
|
||||
{
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public List<TemplateField> Fields { get; set; } = new();
|
||||
public List<TemplateSection> Subsections { get; set; } = new();
|
||||
public List<TemplateSection> Subsections { get; set; } = new(); // For nested sections
|
||||
}
|
||||
|
||||
public class TemplateField
|
||||
|
@ -1,118 +1,87 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace SessionZero.Data;
|
||||
|
||||
[SzfObject(SzfObjectType.Dataset, "dataset")]
|
||||
public class Dataset : SzfObject
|
||||
{
|
||||
public string DatasetType { get; set; } = string.Empty;
|
||||
public string ImageUrl { get; set; } = string.Empty;
|
||||
|
||||
// Collection of entries within this dataset
|
||||
public List<DatasetEntry> Entries { get; set; } = [];
|
||||
|
||||
// Additional metadata fields for .szf compatibility
|
||||
public Dictionary<string, object> Metadata { get; set; } = new();
|
||||
public string ImageUrl { get; set; } = string.Empty; // New field for dataset image
|
||||
public List<DatasetEntry> Entries { get; set; } = new();
|
||||
public Dictionary<string, object> Metadata { get; set; } = new(); // To store other metadata fields
|
||||
|
||||
public override SzfObjectType ObjectType => SzfObjectType.Dataset;
|
||||
|
||||
public override void PopulateFromMetadata(Dictionary<string, SzfField> metadata)
|
||||
{
|
||||
// Call base method to populate common fields
|
||||
base.PopulateFromMetadata(metadata);
|
||||
|
||||
// Populate dataset-specific fields
|
||||
if (metadata.TryGetValue("Type", out var typeField))
|
||||
DatasetType = typeField.Value?.ToString() ?? string.Empty;
|
||||
|
||||
if (metadata.TryGetValue("ImageUrl", out var imageField))
|
||||
ImageUrl = imageField.Value?.ToString() ?? string.Empty;
|
||||
if (metadata.TryGetValue("ImageUrl", out var imageUrlField))
|
||||
ImageUrl = imageUrlField.Value?.ToString() ?? string.Empty;
|
||||
|
||||
// Store any other metadata fields not explicitly mapped
|
||||
foreach (var kvp in metadata)
|
||||
{
|
||||
if (!new[] { "Name", "Version", "GUID", "Description", "Author", "Type", "ImageUrl" }
|
||||
.Contains(kvp.Key, StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
Metadata[kvp.Key] = kvp.Value.Value!;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parses sections specific to the Dataset object, such as entries and their subsections.
|
||||
/// This method is called by the SzfParser to populate Dataset-specific data.
|
||||
/// </summary>
|
||||
/// <param name="sections">A list of all parsed sections from the SZF file.</param>
|
||||
public override void ParseSections(List<SzfSection> sections)
|
||||
{
|
||||
// Dictionary to hold DatasetEntry objects by their name for easy lookup
|
||||
var entriesByName = new Dictionary<string, DatasetEntry>(StringComparer.OrdinalIgnoreCase);
|
||||
var currentEntry = (DatasetEntry?)null;
|
||||
|
||||
// First pass: Identify and populate top-level DatasetEntry objects
|
||||
foreach (var szfSection in sections)
|
||||
{
|
||||
if (szfSection.Name.StartsWith("Entry:", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var entryName = szfSection.Name.Substring("Entry:".Length).Trim();
|
||||
if (string.IsNullOrEmpty(entryName)) continue;
|
||||
currentEntry = new DatasetEntry
|
||||
{
|
||||
Name = szfSection.Name.Replace("Entry:", "").Trim()
|
||||
};
|
||||
|
||||
var newEntry = new DatasetEntry { Name = entryName };
|
||||
foreach (var field in szfSection.Fields)
|
||||
{
|
||||
newEntry.Fields.Add(ConvertToDatasetField(field));
|
||||
currentEntry.Fields.Add(ConvertToDatasetField(field));
|
||||
}
|
||||
|
||||
Entries.Add(newEntry);
|
||||
entriesByName[entryName] = newEntry;
|
||||
Entries.Add(currentEntry);
|
||||
}
|
||||
}
|
||||
|
||||
// Second pass: Populate sections and subsections for each entry
|
||||
foreach (var szfSection in sections)
|
||||
else if (szfSection.Name.StartsWith("Entry.", StringComparison.OrdinalIgnoreCase) && currentEntry != null)
|
||||
{
|
||||
// We are looking for sections like "Entry.EntryName.SectionName" or "Entry.EntryName.SectionName.SubSectionName"
|
||||
if (!szfSection.Name.StartsWith("Entry.", StringComparison.OrdinalIgnoreCase)) continue;
|
||||
|
||||
// Split the section name by '.' to identify parts
|
||||
var nameParts = szfSection.Name.Split('.');
|
||||
|
||||
// Ensure it's a section of an entry (e.g., "Entry.EntryName.Section")
|
||||
if (nameParts.Length < 3 || !nameParts[0].Equals("Entry", StringComparison.OrdinalIgnoreCase)) continue;
|
||||
|
||||
var entryName = nameParts[1];
|
||||
if (!entriesByName.TryGetValue(entryName, out var targetEntry)) continue; // Entry not found, skip
|
||||
|
||||
// We need to build the hierarchy of DatasetSection objects
|
||||
DatasetSection? currentParentSection = null;
|
||||
List<DatasetSection> currentSectionList = targetEntry.Sections;
|
||||
|
||||
for (int i = 2; i < nameParts.Length; i++) // Start from the first section name after "Entry.EntryName"
|
||||
// Handle subsections by finding their parent entry
|
||||
var parts = szfSection.Name.Split('.');
|
||||
if (parts.Length >= 2 && parts[0].Equals("Entry", StringComparison.OrdinalIgnoreCase) &&
|
||||
parts[1].Equals(currentEntry.Name, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
var sectionNamePart = nameParts[i];
|
||||
var existingSection = currentSectionList.FirstOrDefault(s =>
|
||||
s.Name.Equals(sectionNamePart, StringComparison.OrdinalIgnoreCase));
|
||||
var subSection = new DatasetSection
|
||||
{
|
||||
Name = string.Join(".", parts.Skip(2)).Trim() // Name for the subsection
|
||||
};
|
||||
|
||||
if (existingSection == null)
|
||||
{
|
||||
// Create new section
|
||||
var newSection = new DatasetSection { Name = sectionNamePart };
|
||||
currentSectionList.Add(newSection);
|
||||
currentParentSection = newSection;
|
||||
}
|
||||
else
|
||||
{
|
||||
currentParentSection = existingSection;
|
||||
}
|
||||
|
||||
// If this is the last part of the section name, populate its fields
|
||||
if (i == nameParts.Length - 1)
|
||||
{
|
||||
foreach (var field in szfSection.Fields)
|
||||
{
|
||||
currentParentSection.Fields.Add(ConvertToDatasetField(field));
|
||||
}
|
||||
subSection.Fields.Add(ConvertToDatasetField(field));
|
||||
}
|
||||
|
||||
// Move to the next level down in the hierarchy
|
||||
currentSectionList = currentParentSection.Subsections;
|
||||
currentEntry.Sections.Add(subSection);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert SzfField to DatasetField
|
||||
/// </summary>
|
||||
private DatasetField ConvertToDatasetField(SzfField szfField)
|
||||
{
|
||||
// You would typically parse more properties here like Description, IsRequired etc.
|
||||
// For simplicity, only Name, Type and Value are mapped for now.
|
||||
return new DatasetField
|
||||
{
|
||||
Name = szfField.Name,
|
||||
@ -121,9 +90,6 @@ public class Dataset : SzfObject
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse DatasetFieldType from string
|
||||
/// </summary>
|
||||
private DatasetFieldType ParseDatasetFieldType(string typeString)
|
||||
{
|
||||
return typeString.ToLower() switch
|
||||
@ -132,38 +98,78 @@ public class Dataset : SzfObject
|
||||
"text-field" => DatasetFieldType.TextField,
|
||||
"number" => DatasetFieldType.Number,
|
||||
"bool" => DatasetFieldType.Boolean,
|
||||
"group" => DatasetFieldType.Group,
|
||||
"calculated" => DatasetFieldType.Calculated,
|
||||
"system" => DatasetFieldType.System,
|
||||
"dataset-reference" => DatasetFieldType.DatasetReference,
|
||||
"dataset-type" => DatasetFieldType.DatasetType,
|
||||
"dataset-reference-multiple" => DatasetFieldType.DatasetReferenceMultiple,
|
||||
"dataset-type-multiple" => DatasetFieldType.DatasetTypeMultiple,
|
||||
_ => DatasetFieldType.Text
|
||||
"group" => DatasetFieldType.Group,
|
||||
_ => DatasetFieldType.Text // Default to text if unknown
|
||||
};
|
||||
}
|
||||
|
||||
public override void GenerateMetadata(SzfFieldWriter writer)
|
||||
{
|
||||
// Call base to ensure common metadata is generated first if base had any specific generation logic
|
||||
base.GenerateMetadata(writer);
|
||||
|
||||
writer.WriteField("Type", "text", DatasetType);
|
||||
if (!string.IsNullOrEmpty(ImageUrl))
|
||||
writer.WriteField("ImageUrl", "text", ImageUrl);
|
||||
|
||||
// Write any other dynamic metadata
|
||||
foreach (var kvp in Metadata)
|
||||
{
|
||||
writer.WriteField(kvp.Key, "text", kvp.Value); // Assuming text for generic metadata for now
|
||||
}
|
||||
}
|
||||
|
||||
public override void GenerateContent(SzfFieldWriter writer)
|
||||
{
|
||||
foreach (var entry in Entries)
|
||||
{
|
||||
writer.AppendSectionHeader($"Entry: {entry.Name}");
|
||||
|
||||
foreach (var field in entry.Fields)
|
||||
{
|
||||
writer.WriteField(field.Name, field.Type, field.Value);
|
||||
}
|
||||
|
||||
foreach (var section in entry.Sections)
|
||||
{
|
||||
GenerateDatasetSection(writer, section, $"Entry.{entry.Name}");
|
||||
}
|
||||
|
||||
writer.AppendLine();
|
||||
}
|
||||
}
|
||||
|
||||
private void GenerateDatasetSection(SzfFieldWriter writer, DatasetSection section, string parentPath)
|
||||
{
|
||||
var sectionPath = $"{parentPath}.{section.Name}";
|
||||
writer.AppendSectionHeader(sectionPath);
|
||||
|
||||
foreach (var field in section.Fields)
|
||||
{
|
||||
writer.WriteField(field.Name, field.Type, field.Value);
|
||||
}
|
||||
|
||||
foreach (var subsection in section.Subsections)
|
||||
{
|
||||
GenerateDatasetSection(writer, subsection, sectionPath);
|
||||
}
|
||||
}
|
||||
|
||||
public override SzfValidationResult Validate()
|
||||
{
|
||||
var result = base.Validate();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(DatasetType))
|
||||
result.AddError("DatasetType is required");
|
||||
result.AddError("DatasetType is required for Dataset");
|
||||
|
||||
// Validate entries
|
||||
var entryNames = new HashSet<string>();
|
||||
foreach (var entry in Entries)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(entry.Name))
|
||||
{
|
||||
result.AddError("All entries must have a name");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!entryNames.Add(entry.Name))
|
||||
result.AddError($"Duplicate entry name: {entry.Name}");
|
||||
}
|
||||
if (!Entries.Any())
|
||||
result.AddWarning("Dataset contains no entries.");
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -172,36 +178,30 @@ public class Dataset : SzfObject
|
||||
public class DatasetEntry
|
||||
{
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public List<DatasetField> Fields { get; set; } = [];
|
||||
public List<DatasetSection> Sections { get; set; } = [];
|
||||
public List<DatasetField> Fields { get; set; } = new();
|
||||
public List<DatasetSection> Sections { get; set; } = new(); // For nested sections within an entry
|
||||
}
|
||||
|
||||
public class DatasetSection
|
||||
{
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public List<DatasetField> Fields { get; set; } = [];
|
||||
public List<DatasetSection> Subsections { get; set; } = [];
|
||||
public List<DatasetField> Fields { get; set; } = new();
|
||||
public List<DatasetSection> Subsections { get; set; } = new();
|
||||
}
|
||||
|
||||
public class DatasetField
|
||||
{
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public DatasetFieldType Type { get; set; }
|
||||
public object? Value { get; set; } = null;
|
||||
public object? Value { get; set; }
|
||||
public string? Description { get; set; }
|
||||
public bool IsRequired { get; set; } = false;
|
||||
public bool IsRequired { get; set; }
|
||||
public object? DefaultValue { get; set; }
|
||||
|
||||
// For calculated fields
|
||||
public string? Formula { get; set; }
|
||||
|
||||
// For dataset reference fields
|
||||
public string? ReferencedDatasetId { get; set; }
|
||||
public string? ReferencedDatasetType { get; set; }
|
||||
public bool AllowMultiple { get; set; } = false;
|
||||
|
||||
// For group fields
|
||||
public List<DatasetField> GroupFields { get; set; } = [];
|
||||
public string? ReferencedDatasetId { get; set; } // For dataset-reference types, stores the ID
|
||||
public string? ReferencedDatasetType { get; set; } // For dataset-type types, stores the type
|
||||
public bool AllowMultiple { get; set; }
|
||||
public List<DatasetField> GroupFields { get; set; } = new(); // For group fields
|
||||
}
|
||||
|
||||
public enum DatasetFieldType
|
||||
@ -210,42 +210,50 @@ public enum DatasetFieldType
|
||||
TextField,
|
||||
Number,
|
||||
Boolean,
|
||||
Group,
|
||||
Calculated,
|
||||
System,
|
||||
DatasetReference,
|
||||
DatasetType,
|
||||
DatasetReferenceMultiple,
|
||||
DatasetTypeMultiple
|
||||
DatasetTypeMultiple,
|
||||
Group
|
||||
}
|
||||
|
||||
// Supporting classes for dataset management
|
||||
public class DatasetReference
|
||||
{
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public Guid Guid { get; set; }
|
||||
public string Version { get; set; } = string.Empty;
|
||||
public string Version { get; set; } = "1.0.0";
|
||||
|
||||
public override string ToString() => $"{Name}|{Guid}|{Version}";
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{Name}|{Guid}|{Version}";
|
||||
}
|
||||
|
||||
public static DatasetReference? Parse(string reference)
|
||||
{
|
||||
var parts = reference.Split('|');
|
||||
if (parts.Length != 3 || !Guid.TryParse(parts[1], out var id))
|
||||
if (string.IsNullOrWhiteSpace(reference))
|
||||
return null;
|
||||
|
||||
var parts = reference.Split('|');
|
||||
if (parts.Length != 3)
|
||||
return null; // Invalid format
|
||||
|
||||
if (Guid.TryParse(parts[1], out var guid))
|
||||
{
|
||||
return new DatasetReference
|
||||
{
|
||||
Name = parts[0],
|
||||
Guid = id,
|
||||
Guid = guid,
|
||||
Version = parts[2]
|
||||
};
|
||||
}
|
||||
|
||||
return null; // Invalid GUID format
|
||||
}
|
||||
}
|
||||
|
||||
public class DatasetValidationResult
|
||||
public class DatasetValidationResult : SzfValidationResult
|
||||
{
|
||||
public bool IsValid { get; set; }
|
||||
public List<string> Errors { get; set; } = [];
|
||||
public List<string> Warnings { get; set; } = [];
|
||||
// Specific validation results for datasets can go here if needed
|
||||
}
|
98
SessionZero/Data/SzfFieldWriter.cs
Normal file
98
SessionZero/Data/SzfFieldWriter.cs
Normal file
@ -0,0 +1,98 @@
|
||||
// SzfFieldWriter.cs
|
||||
|
||||
using System.Text;
|
||||
|
||||
namespace SessionZero.Data;
|
||||
|
||||
/// <summary>
|
||||
/// Helper class to write fields to a StringBuilder following SZF format,
|
||||
/// respecting generator options like indentation.
|
||||
/// </summary>
|
||||
public class SzfFieldWriter
|
||||
{
|
||||
public readonly StringBuilder Builder;
|
||||
public readonly SzfGeneratorOptions Options;
|
||||
|
||||
public SzfFieldWriter(StringBuilder builder, SzfGeneratorOptions options)
|
||||
{
|
||||
Builder = builder;
|
||||
Options = options;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a generic field with a string type.
|
||||
/// </summary>
|
||||
public void WriteField(string name, string type, object? value)
|
||||
{
|
||||
if (!Options.IncludeEmptyFields && (value == null || string.IsNullOrEmpty(value.ToString())))
|
||||
{
|
||||
return; // Skip empty fields if option is set
|
||||
}
|
||||
|
||||
var formattedValue = FormatFieldValue(value, type);
|
||||
|
||||
if (Options.IndentFields)
|
||||
{
|
||||
Builder.AppendLine($"{Options.Indent}{name} ({type}) = {formattedValue}");
|
||||
}
|
||||
else
|
||||
{
|
||||
Builder.AppendLine($"{name} ({type}) = {formattedValue}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a field with a DatasetFieldType.
|
||||
/// </summary>
|
||||
public void WriteField(string name, DatasetFieldType type, object? value)
|
||||
{
|
||||
var typeString = type switch
|
||||
{
|
||||
DatasetFieldType.Text => "text",
|
||||
DatasetFieldType.TextField => "text-field",
|
||||
DatasetFieldType.Number => "number",
|
||||
DatasetFieldType.Boolean => "bool",
|
||||
DatasetFieldType.Group => "group",
|
||||
DatasetFieldType.Calculated => "calculated",
|
||||
DatasetFieldType.System => "system",
|
||||
DatasetFieldType.DatasetReference => "dataset-reference",
|
||||
DatasetFieldType.DatasetType => "dataset-type",
|
||||
DatasetFieldType.DatasetReferenceMultiple => "dataset-reference-multiple",
|
||||
DatasetFieldType.DatasetTypeMultiple => "dataset-type-multiple",
|
||||
_ => "text" // Default or unknown types
|
||||
};
|
||||
WriteField(name, typeString, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Formats field values based on their declared type for SZF output.
|
||||
/// </summary>
|
||||
private string FormatFieldValue(object? value, string fieldType)
|
||||
{
|
||||
if (value == null)
|
||||
return string.Empty;
|
||||
|
||||
return fieldType.ToLower() switch
|
||||
{
|
||||
"bool" => (bool)value ? "true" : "false",
|
||||
"number" => value.ToString() ?? "0",
|
||||
_ => value.ToString() ?? string.Empty
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Appends a new line to the string builder.
|
||||
/// </summary>
|
||||
public void AppendLine()
|
||||
{
|
||||
Builder.AppendLine();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Appends a section header to the string builder.
|
||||
/// </summary>
|
||||
public void AppendSectionHeader(string header)
|
||||
{
|
||||
Builder.AppendLine($"[{header}]");
|
||||
}
|
||||
}
|
@ -1,3 +1,4 @@
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
|
||||
namespace SessionZero.Data;
|
||||
@ -17,15 +18,16 @@ public class SzfGenerator
|
||||
public string Generate(SzfObject obj)
|
||||
{
|
||||
var builder = new StringBuilder();
|
||||
var writer = new SzfFieldWriter(builder, _options);
|
||||
|
||||
// Generate header
|
||||
GenerateHeader(builder, obj);
|
||||
GenerateHeader(writer, obj);
|
||||
|
||||
// Generate metadata section
|
||||
GenerateMetadataSection(builder, obj);
|
||||
GenerateMetadataSection(writer, obj);
|
||||
|
||||
// Generate type-specific content
|
||||
GenerateTypeSpecificContent(builder, obj);
|
||||
GenerateTypeSpecificContent(writer, obj);
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
@ -33,179 +35,48 @@ public class SzfGenerator
|
||||
/// <summary>
|
||||
/// Generate the SZF header (!type: and !schema:)
|
||||
/// </summary>
|
||||
private void GenerateHeader(StringBuilder builder, SzfObject obj)
|
||||
private void GenerateHeader(SzfFieldWriter writer, SzfObject obj)
|
||||
{
|
||||
var objectTypeString = obj.ObjectType switch
|
||||
{
|
||||
SzfObjectType.Dataset => "dataset",
|
||||
SzfObjectType.CharacterTemplate => "character_template",
|
||||
SzfObjectType.Character => "character",
|
||||
SzfObjectType.Session => "session",
|
||||
_ => throw new SzfGenerateException($"Unsupported object type: {obj.ObjectType}")
|
||||
};
|
||||
var type = obj.GetType();
|
||||
var attribute = type.GetCustomAttribute<SzfObjectAttribute>();
|
||||
|
||||
builder.AppendLine($"!type: {objectTypeString}");
|
||||
builder.AppendLine($"!schema: {obj.SchemaVersion}");
|
||||
builder.AppendLine();
|
||||
if (attribute == null)
|
||||
{
|
||||
throw new SzfGenerateException(
|
||||
$"Type {type.Name} does not have SzfObjectAttribute, cannot determine type string.");
|
||||
}
|
||||
|
||||
writer.Builder.AppendLine($"!type: {attribute.TypeString}");
|
||||
writer.Builder.AppendLine($"!schema: {obj.SchemaVersion}");
|
||||
writer.Builder.AppendLine();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate the common metadata section
|
||||
/// </summary>
|
||||
private void GenerateMetadataSection(StringBuilder builder, SzfObject obj)
|
||||
private void GenerateMetadataSection(SzfFieldWriter writer, SzfObject obj)
|
||||
{
|
||||
builder.AppendLine("[Metadata]");
|
||||
writer.AppendSectionHeader("Metadata");
|
||||
|
||||
// Standard metadata fields
|
||||
WriteField(builder, "Name", "text", obj.Name);
|
||||
WriteField(builder, "Version", "text", obj.Version);
|
||||
WriteField(builder, "GUID", "text", obj.Id.ToString());
|
||||
WriteField(builder, "Description", "text-field", obj.Description);
|
||||
WriteField(builder, "Author", "text", obj.Author);
|
||||
writer.WriteField("Name", "text", obj.Name);
|
||||
writer.WriteField("Version", "text", obj.Version);
|
||||
writer.WriteField("GUID", "text", obj.Id.ToString());
|
||||
writer.WriteField("Description", "text-field", obj.Description);
|
||||
writer.WriteField("Author", "text", obj.Author);
|
||||
|
||||
// Type-specific metadata
|
||||
GenerateTypeSpecificMetadata(builder, obj);
|
||||
// Type-specific metadata delegated to the object itself
|
||||
obj.GenerateMetadata(writer);
|
||||
|
||||
builder.AppendLine();
|
||||
writer.AppendLine();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate type-specific metadata fields
|
||||
/// Generate type-specific content sections delegated to the object itself
|
||||
/// </summary>
|
||||
private void GenerateTypeSpecificMetadata(StringBuilder builder, SzfObject obj)
|
||||
private void GenerateTypeSpecificContent(SzfFieldWriter writer, SzfObject obj)
|
||||
{
|
||||
switch (obj)
|
||||
{
|
||||
case Dataset dataset:
|
||||
WriteField(builder, "Type", "text", dataset.DatasetType);
|
||||
if (!string.IsNullOrEmpty(dataset.ImageUrl))
|
||||
WriteField(builder, "ImageUrl", "text", dataset.ImageUrl);
|
||||
break;
|
||||
// Add other types as they're implemented
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate type-specific content sections
|
||||
/// </summary>
|
||||
private void GenerateTypeSpecificContent(StringBuilder builder, SzfObject obj)
|
||||
{
|
||||
switch (obj)
|
||||
{
|
||||
case Dataset dataset:
|
||||
GenerateDatasetContent(builder, dataset);
|
||||
break;
|
||||
// Add other types as they're implemented
|
||||
default:
|
||||
throw new SzfGenerateException($"Content generation not implemented for type: {obj.GetType().Name}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate dataset-specific content (entries, sections, fields)
|
||||
/// </summary>
|
||||
private void GenerateDatasetContent(StringBuilder builder, Dataset dataset)
|
||||
{
|
||||
foreach (var entry in dataset.Entries)
|
||||
{
|
||||
// Entry header
|
||||
builder.AppendLine($"[Entry: {entry.Name}]");
|
||||
|
||||
// Entry fields
|
||||
foreach (var field in entry.Fields)
|
||||
{
|
||||
WriteDatasetField(builder, field);
|
||||
}
|
||||
|
||||
// Entry sections
|
||||
foreach (var section in entry.Sections)
|
||||
{
|
||||
GenerateDatasetSection(builder, section, $"Entry.{entry.Name}");
|
||||
}
|
||||
|
||||
builder.AppendLine();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate dataset sections recursively
|
||||
/// </summary>
|
||||
private void GenerateDatasetSection(StringBuilder builder, DatasetSection section, string parentPath)
|
||||
{
|
||||
var sectionPath = $"{parentPath}.{section.Name}";
|
||||
builder.AppendLine($"[{sectionPath}]");
|
||||
|
||||
// Section fields
|
||||
foreach (var field in section.Fields)
|
||||
{
|
||||
WriteDatasetField(builder, field);
|
||||
}
|
||||
|
||||
// Subsections
|
||||
foreach (var subsection in section.Subsections)
|
||||
{
|
||||
GenerateDatasetSection(builder, subsection, sectionPath);
|
||||
}
|
||||
|
||||
builder.AppendLine();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a dataset field in SZF format
|
||||
/// </summary>
|
||||
private void WriteDatasetField(StringBuilder builder, DatasetField field)
|
||||
{
|
||||
var typeString = field.Type switch
|
||||
{
|
||||
DatasetFieldType.Text => "text",
|
||||
DatasetFieldType.TextField => "text-field",
|
||||
DatasetFieldType.Number => "number",
|
||||
DatasetFieldType.Boolean => "bool",
|
||||
DatasetFieldType.Group => "group",
|
||||
DatasetFieldType.Calculated => "calculated",
|
||||
DatasetFieldType.System => "system",
|
||||
DatasetFieldType.DatasetReference => "dataset-reference",
|
||||
DatasetFieldType.DatasetType => "dataset-type",
|
||||
DatasetFieldType.DatasetReferenceMultiple => "dataset-reference-multiple",
|
||||
DatasetFieldType.DatasetTypeMultiple => "dataset-type-multiple",
|
||||
_ => "text"
|
||||
};
|
||||
|
||||
var value = FormatFieldValue(field.Value, field.Type);
|
||||
WriteField(builder, field.Name, typeString, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Write a field in SZF format: Name (type) = value
|
||||
/// </summary>
|
||||
private void WriteField(StringBuilder builder, string name, string type, object? value)
|
||||
{
|
||||
var formattedValue = value?.ToString() ?? string.Empty;
|
||||
|
||||
if (_options.IndentFields)
|
||||
{
|
||||
builder.AppendLine($"{_options.Indent}{name} ({type}) = {formattedValue}");
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.AppendLine($"{name} ({type}) = {formattedValue}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Format field values based on their type
|
||||
/// </summary>
|
||||
private string FormatFieldValue(object? value, DatasetFieldType fieldType)
|
||||
{
|
||||
if (value == null)
|
||||
return string.Empty;
|
||||
|
||||
return fieldType switch
|
||||
{
|
||||
DatasetFieldType.Boolean => (bool)value ? "true" : "false",
|
||||
DatasetFieldType.Number => value.ToString() ?? "0",
|
||||
_ => value.ToString() ?? string.Empty
|
||||
};
|
||||
obj.GenerateContent(writer);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,3 +1,8 @@
|
||||
// SzfObject.cs
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace SessionZero.Data;
|
||||
|
||||
public abstract class SzfObject
|
||||
@ -22,6 +27,26 @@ public abstract class SzfObject
|
||||
/// <param name="sections">A list of all parsed sections from the SZF file.</param>
|
||||
public abstract void ParseSections(List<SzfSection> sections);
|
||||
|
||||
/// <summary>
|
||||
/// Virtual method for SzfObjects to generate their specific metadata fields.
|
||||
/// Override this in derived classes to add custom metadata to the [Metadata] section.
|
||||
/// </summary>
|
||||
/// <param name="writer">The SzfFieldWriter instance to write fields.</param>
|
||||
public virtual void GenerateMetadata(SzfFieldWriter writer)
|
||||
{
|
||||
// Default implementation does nothing, derived classes can override.
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Virtual method for SzfObjects to generate their specific content sections.
|
||||
/// Override this in derived classes to add custom sections and fields.
|
||||
/// </summary>
|
||||
/// <param name="writer">The SzfFieldWriter instance to write fields and manage sections.</param>
|
||||
public virtual void GenerateContent(SzfFieldWriter writer)
|
||||
{
|
||||
// Default implementation does nothing, derived classes can override.
|
||||
}
|
||||
|
||||
public virtual SzfValidationResult Validate()
|
||||
{
|
||||
var result = new SzfValidationResult { IsValid = true };
|
||||
|
@ -3,20 +3,26 @@
|
||||
@using Microsoft.Extensions.Logging
|
||||
@inject SzfParser SzfParser
|
||||
@inject ILogger<SzfParser> Logger
|
||||
@inject SzfGenerator SzfGenerator
|
||||
|
||||
<h1>SZF Parser Test Page</h1>
|
||||
<h1>SZF Parser and Generator Test Page</h1>
|
||||
|
||||
<div>
|
||||
<div>
|
||||
<div class="test-container">
|
||||
<div class="input-section">
|
||||
<h2>SZF Input</h2>
|
||||
<div>
|
||||
<textarea id="szf-input" @bind="szfCode" rows="20"></textarea>
|
||||
</div>
|
||||
<button @onclick="ParseSzf">Parse SZF</button>
|
||||
</div>
|
||||
<div>
|
||||
@if (parsedObject != null)
|
||||
{
|
||||
<button @onclick="GenerateSzf">Generate SZF from Parsed Object</button>
|
||||
}
|
||||
</div>
|
||||
<div class="output-section">
|
||||
<h2>Parsed Object Data</h2>
|
||||
@if (parsedObject != null)
|
||||
{
|
||||
<table>
|
||||
<tbody>
|
||||
<tr><th>Object Type</th><td>@parsedObject.ObjectType</td></tr>
|
||||
@ -105,7 +111,7 @@
|
||||
<tr>
|
||||
<td>@reqDataset.Alias</td>
|
||||
<td>@reqDataset.Reference?.Name</td>
|
||||
<td>@reqDataset.Reference?.Guid</td> @* Changed from DatasetId to Guid *@
|
||||
<td>@reqDataset.Reference?.Guid</td>
|
||||
<td>@reqDataset.Reference?.Version</td>
|
||||
</tr>
|
||||
}
|
||||
@ -136,25 +142,81 @@
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
<div class="generated-output-section">
|
||||
<h2>Generated SZF Output</h2>
|
||||
@if (!string.IsNullOrEmpty(generatedSzfOutput))
|
||||
{
|
||||
<textarea id="generated-szf-output" @bind="generatedSzfOutput" rows="20" readonly></textarea>
|
||||
}
|
||||
else
|
||||
{
|
||||
<p>No SZF has been generated yet.</p>
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<div class="logs-section">
|
||||
<h2>Logs</h2>
|
||||
<pre>@string.Join("\n", logMessages)</pre>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.test-container {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr 1fr; /* Three columns for input, parsed data, generated output */
|
||||
gap: 20px;
|
||||
}
|
||||
|
||||
.input-section, .output-section, .generated-output-section {
|
||||
border: 1px solid #ccc;
|
||||
padding: 15px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
textarea {
|
||||
width: 100%;
|
||||
box-sizing: border-box; /* Include padding and border in the element's total width and height */
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
th, td {
|
||||
border: 1px solid #ddd;
|
||||
padding: 8px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
th {
|
||||
background-color: #f2f2f2;
|
||||
}
|
||||
|
||||
.logs-section {
|
||||
margin-top: 20px;
|
||||
border: 1px solid #ccc;
|
||||
padding: 15px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
pre {
|
||||
white-space: pre-wrap; /* Ensures logs wrap */
|
||||
word-wrap: break-word;
|
||||
}
|
||||
</style>
|
||||
|
||||
@code {
|
||||
private string szfCode = string.Empty;
|
||||
private SzfObject? parsedObject;
|
||||
private string generatedSzfOutput = string.Empty; // New field for generated output
|
||||
private List<string> logMessages = new List<string>();
|
||||
private List<string> errorMessages = new List<string>();
|
||||
|
||||
private void ParseSzf()
|
||||
{
|
||||
logMessages.Clear();
|
||||
errorMessages.Clear();
|
||||
parsedObject = null;
|
||||
|
||||
ClearState(); // Clear previous states
|
||||
Log("Starting SZF parsing...");
|
||||
|
||||
if (string.IsNullOrWhiteSpace(szfCode))
|
||||
@ -180,6 +242,38 @@
|
||||
}
|
||||
}
|
||||
|
||||
private void GenerateSzf()
|
||||
{
|
||||
generatedSzfOutput = string.Empty; // Clear previous generated output
|
||||
if (parsedObject == null)
|
||||
{
|
||||
Log("No object to generate from. Please parse an SZF first.");
|
||||
return;
|
||||
}
|
||||
|
||||
Log("Starting SZF generation...");
|
||||
try
|
||||
{
|
||||
// Use the ToSzfString() method on the parsed object, which uses SzfGenerator internally
|
||||
generatedSzfOutput = parsedObject.ToSzfString();
|
||||
Log("SZF content generated successfully.");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
const string message = "An error occurred during generation.";
|
||||
LogError(message, ex);
|
||||
errorMessages.Add($"{message} See logs for details.");
|
||||
}
|
||||
}
|
||||
|
||||
private void ClearState()
|
||||
{
|
||||
logMessages.Clear();
|
||||
errorMessages.Clear();
|
||||
parsedObject = null;
|
||||
generatedSzfOutput = string.Empty;
|
||||
}
|
||||
|
||||
private void Log(string message)
|
||||
{
|
||||
Logger.LogInformation(message);
|
3
SessionZero/Pages/SzfParseTest.razor.css
Normal file
3
SessionZero/Pages/SzfParseTest.razor.css
Normal file
@ -0,0 +1,3 @@
|
||||
.main-content {
|
||||
text-align: left; !important;
|
||||
}
|
@ -15,6 +15,7 @@ builder.Services.AddBlazoredLocalStorage();
|
||||
|
||||
// Register our services
|
||||
builder.Services.AddScoped<SzfParser>();
|
||||
builder.Services.AddScoped<SzfGenerator>();
|
||||
|
||||
|
||||
await builder.Build().RunAsync();
|
Loading…
Reference in New Issue
Block a user