Skip to content

Commit

Permalink
add - prt|brk|doc - Added PropertyInfo (pt. 2)
Browse files Browse the repository at this point in the history
---

We've added PropertyInfo to attempt to make a refactor for the parser.

---

Type: add
Breaking: True
Doc Required: True
Backport Required: False
Part: 1/2
  • Loading branch information
AptiviCEO committed Oct 3, 2024
1 parent d4f0421 commit 2b92059
Show file tree
Hide file tree
Showing 8 changed files with 37 additions and 108 deletions.
66 changes: 16 additions & 50 deletions VisualCard.Calendar/Parsers/VCalendarParser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -106,33 +106,20 @@ public Parts.Calendar Parse()

try
{
// Now, parse a line
if (!_value.Contains(VcardConstants._argumentDelimiter))
throw new ArgumentException("The line must contain an argument delimiter.");
string value = _value.Substring(_value.IndexOf(VcardConstants._argumentDelimiter) + 1);
string prefixWithArgs = _value.Substring(0, _value.IndexOf(VcardConstants._argumentDelimiter));
string prefix = (prefixWithArgs.Contains(';') ? prefixWithArgs.Substring(0, prefixWithArgs.IndexOf(';')) : prefixWithArgs).ToUpper();
string args = prefixWithArgs.Contains(';') ? prefixWithArgs.Substring(prefix.Length + 1) : "";
string[] splitArgs = args.Split([VcardConstants._fieldDelimiter], StringSplitOptions.RemoveEmptyEntries);
string[] splitValues = value.Split([VcardConstants._fieldDelimiter], StringSplitOptions.RemoveEmptyEntries);
bool isWithType = splitArgs.Length > 0;
List<ArgumentInfo> finalArgs = [];

// Extract the group name
string group = prefix.Contains(".") ? prefix.Substring(0, prefix.IndexOf(".")) : "";
prefix = prefix.RemovePrefix($"{group}.");
// Now, parse a property
var info = new PropertyInfo(_value, CalendarVersion);

// Check to see if we have a BEGIN or an END prefix
if (prefix == VcardConstants._beginSpecifier)
if (info.Prefix == VcardConstants._beginSpecifier)
{
string finalType = value.ToUpper();
string finalType = info.Value.ToUpper();
begins.Add((finalType, GetCalendarInheritedInstance(finalType)));
continue;
}
else if (prefix == VcardConstants._endSpecifier)
else if (info.Prefix == VcardConstants._endSpecifier)
{
string expectedType = begins[begins.Count - 1].Item1;
if (value == expectedType)
if (info.Value == expectedType)
{
if (begins.Count == 1)
SaveLastSubPart(subPart, ref calendar);
Expand All @@ -144,37 +131,16 @@ public Parts.Calendar Parse()
begins.RemoveAt(begins.Count - 1);
}
else
throw new ArgumentException($"Ending mismatch: Expected {expectedType} vs. actual {value}");
throw new ArgumentException($"Ending mismatch: Expected {expectedType} vs. actual {info.Value}");
continue;
}

// Get the part type
bool xNonstandard = prefix.StartsWith(VcardConstants._xSpecifier);
bool specifierRequired = CalendarVersion.Major >= 3;
// Get the type and its properties
Type calendarType = subPart is not null ? subPart.GetType() : calendar.GetType();
var (type, enumeration, classType, fromString, defaultType, defaultValue, defaultValueType, extraAllowedTypes, allowedValues) = VCalendarParserTools.GetPartType(xNonstandard ? VcardConstants._xSpecifier : prefix, VCalendarParserTools.GetObjectTypeFromType(calendarType), CalendarVersion);

// Handle arguments
if (isWithType)
{
// Finalize the arguments
var argsStr = splitArgs.Except(
splitArgs.Where((arg) =>
arg.StartsWith(VcardConstants._valueArgumentSpecifier) ||
arg.StartsWith(VcardConstants._typeArgumentSpecifier) ||
CalendarVersion.Major == 2 && !arg.Contains(VcardConstants._argumentValueDelimiter)
)
);
foreach (string arg in argsStr)
{
string keyStr = arg.Substring(0, arg.IndexOf(VcardConstants._argumentValueDelimiter));
string valueStr = arg.RemovePrefix($"{keyStr}{VcardConstants._argumentValueDelimiter}");
finalArgs.Add(new(keyStr, valueStr));
}
}
var (type, enumeration, classType, fromString, defaultType, defaultValue, defaultValueType, extraAllowedTypes, allowedValues) = VCalendarParserTools.GetPartType(info.Prefix, VCalendarParserTools.GetObjectTypeFromType(calendarType), CalendarVersion);

// Check the type for allowed types
string[] elementTypes = VcardCommonTools.GetTypes(splitArgs, defaultType, specifierRequired);
string[] elementTypes = VcardCommonTools.GetTypes(info.ArgumentsFiltered, defaultType);
foreach (string elementType in elementTypes)
{
string elementTypeUpper = elementType.ToUpper();
Expand All @@ -183,8 +149,8 @@ public Parts.Calendar Parse()
}

// Handle the part type, and extract the value
string valueType = VcardCommonTools.GetFirstValue(splitArgs, defaultValueType, VcardConstants._valueArgumentSpecifier);
string finalValue = VcardCommonTools.ProcessStringValue(value, valueType, calendarVersion.Major == 1 ? ';' : ',');
string valueType = VcardCommonTools.GetFirstValue(info.ArgumentsFiltered, defaultValueType, VcardConstants._valueArgumentSpecifier);
string finalValue = VcardCommonTools.ProcessStringValue(info.Value, valueType, calendarVersion.Major == 1 ? ';' : ',');

// Check for allowed values
if (allowedValues.Length != 0)
Expand All @@ -210,7 +176,7 @@ public Parts.Calendar Parse()
continue;

// Set the string for real
var stringValueInfo = new CalendarValueInfo<string>([.. finalArgs], elementTypes, group, valueType, finalValue);
var stringValueInfo = new CalendarValueInfo<string>(info.ArgumentsFiltered, elementTypes, info.Group, valueType, finalValue);
if (subPart is not null)
subPart.AddString(stringType, stringValueInfo);
else
Expand All @@ -228,7 +194,7 @@ public Parts.Calendar Parse()
double finalDouble = double.Parse(finalValue);

// Set the integer for real
var stringValueInfo = new CalendarValueInfo<double>([.. finalArgs], elementTypes, group, valueType, finalDouble);
var stringValueInfo = new CalendarValueInfo<double>(info.ArgumentsFiltered, elementTypes, info.Group, valueType, finalDouble);
if (subPart is not null)
subPart.AddInteger(integerType, stringValueInfo);
else
Expand All @@ -246,8 +212,8 @@ public Parts.Calendar Parse()
continue;

// Now, get the part info
finalValue = partsArrayType is CalendarPartsArrayEnum.IanaNames or CalendarPartsArrayEnum.NonstandardNames ? _value : value;
var partInfo = fromString(finalValue, [.. finalArgs], elementTypes, group, valueType, CalendarVersion);
finalValue = partsArrayType is CalendarPartsArrayEnum.IanaNames or CalendarPartsArrayEnum.NonstandardNames ? _value : info.Value;
var partInfo = fromString(finalValue, info.ArgumentsFiltered, elementTypes, info.Group, valueType, CalendarVersion);

// Set the array for real
if (subPart is not null)
Expand Down
6 changes: 3 additions & 3 deletions VisualCard.Calendar/Parts/Calendar.cs
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,7 @@ internal string SaveToString(Version version, Dictionary<CalendarPartsArrayEnum,
foreach (var part in array)
{
var partBuilder = new StringBuilder();
string partArguments = CalendarBuilderTools.BuildArguments(part, version, defaultType, defaultValueType);
string partArguments = CalendarBuilderTools.BuildArguments(part, defaultType, defaultValueType);
string[] partArgumentsLines = partArguments.SplitNewLines();
string group = part.Group;
if (!string.IsNullOrEmpty(group))
Expand Down Expand Up @@ -331,7 +331,7 @@ internal string SaveToString(Version version, Dictionary<CalendarPartsArrayEnum,
foreach (var part in array)
{
var partBuilder = new StringBuilder();
string partArguments = CalendarBuilderTools.BuildArguments(part, version, defaultType, defaultValueType);
string partArguments = CalendarBuilderTools.BuildArguments(part, defaultType, defaultValueType);
string[] partArgumentsLines = partArguments.SplitNewLines();
string group = part.Group;
if (!string.IsNullOrEmpty(group))
Expand Down Expand Up @@ -363,7 +363,7 @@ internal string SaveToString(Version version, Dictionary<CalendarPartsArrayEnum,
{
var partBuilder = new StringBuilder();
string partRepresentation = part.ToStringVcalendarInternal(version);
string partArguments = CalendarBuilderTools.BuildArguments(part, version, defaultType, defaultValueType);
string partArguments = CalendarBuilderTools.BuildArguments(part, defaultType, defaultValueType);
string[] partArgumentsLines = partArguments.SplitNewLines();
string group = part.Group;
if (!string.IsNullOrEmpty(group))
Expand Down
8 changes: 4 additions & 4 deletions VisualCard.Calendar/Parts/CalendarBuilderTools.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,15 @@ namespace VisualCard.Calendar.Parts
{
internal static class CalendarBuilderTools
{
internal static string BuildArguments(BaseCalendarPartInfo partInfo, Version cardVersion, string defaultType, string defaultValue)
internal static string BuildArguments(BaseCalendarPartInfo partInfo, string defaultType, string defaultValue)
{
string extraKeyName =
(partInfo is XNameInfo xName ? xName.XKeyName :
partInfo is ExtraInfo exName ? exName.KeyName : "") ?? "";
return CardBuilderTools.BuildArguments(partInfo.ElementTypes, partInfo.ValueType, -1, partInfo.Arguments, extraKeyName, cardVersion, defaultType, defaultValue);
return CardBuilderTools.BuildArguments(partInfo.ElementTypes, partInfo.ValueType, partInfo.Arguments, extraKeyName, defaultType, defaultValue);
}

internal static string BuildArguments<TValue>(CalendarValueInfo<TValue> partInfo, Version cardVersion, string defaultType, string defaultValue) =>
CardBuilderTools.BuildArguments(partInfo.ElementTypes, partInfo.ValueType, -1, partInfo.Arguments, "", cardVersion, defaultType, defaultValue);
internal static string BuildArguments<TValue>(CalendarValueInfo<TValue> partInfo, string defaultType, string defaultValue) =>
CardBuilderTools.BuildArguments(partInfo.ElementTypes, partInfo.ValueType, partInfo.Arguments, "", defaultType, defaultValue);
}
}
2 changes: 1 addition & 1 deletion VisualCard/Parsers/Arguments/ArgumentInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ public override int GetHashCode()

internal ArgumentInfo(string kvp)
{
if (!kvp.Contains(VcardConstants._argumentValueDelimiter))
if (kvp.Contains(VcardConstants._argumentValueDelimiter))
{
string keyStr = kvp.Substring(0, kvp.IndexOf(VcardConstants._argumentValueDelimiter));
string valueStr = kvp.RemovePrefix($"{keyStr}{VcardConstants._argumentValueDelimiter}");
Expand Down
2 changes: 1 addition & 1 deletion VisualCard/Parsers/Arguments/PropertyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public class PropertyInfo
private string prefix = "";
private string group = "";
private ArgumentInfo[] arguments = [];
private Version version;
private readonly Version version;

/// <summary>
/// Raw value
Expand Down
4 changes: 2 additions & 2 deletions VisualCard/Parsers/VcardCommonTools.cs
Original file line number Diff line number Diff line change
Expand Up @@ -442,7 +442,7 @@ internal static string GetTypesString(ArgumentInfo[] args, string @default, bool
var ArgType = args.Where((arg) => arg.Key == VcardConstants._typeArgumentSpecifier || string.IsNullOrEmpty(arg.Key)).ToArray();

// Trying to specify type without TYPE= is illegal according to RFC2426 in vCard 3.0 and 4.0
if (ArgType.Length > 0 && ArgType[0].Key == VcardConstants._typeArgumentSpecifier && isSpecifierRequired)
if (ArgType.Length > 0 && string.IsNullOrEmpty(ArgType[0].Key) && isSpecifierRequired)
throw new InvalidDataException("Type must be prepended with TYPE=");

// Flatten the strings
Expand All @@ -454,7 +454,7 @@ internal static string GetTypesString(ArgumentInfo[] args, string @default, bool
// Get the type from the split argument
string Type =
ArgType.Length > 0 ?
string.Join(VcardConstants._valueDelimiter.ToString(), flattened.Select((arg) => arg.Substring(VcardConstants._typeArgumentSpecifier.Length))) :
string.Join(VcardConstants._valueDelimiter.ToString(), flattened) :
@default;

// Return the type
Expand Down
4 changes: 2 additions & 2 deletions VisualCard/Parts/Card.cs
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,7 @@ public string SaveToString()
foreach (var part in array)
{
var partBuilder = new StringBuilder();
string partArguments = CardBuilderTools.BuildArguments(part, version, defaultType, defaultValueType);
string partArguments = CardBuilderTools.BuildArguments(part, defaultType, defaultValueType);
string[] partArgumentsLines = partArguments.SplitNewLines();
string group = part.Group;
if (!string.IsNullOrEmpty(group))
Expand Down Expand Up @@ -250,7 +250,7 @@ public string SaveToString()
{
var partBuilder = new StringBuilder();
string partRepresentation = part.ToStringVcardInternal(version);
string partArguments = CardBuilderTools.BuildArguments(part, version, defaultType, defaultValueType);
string partArguments = CardBuilderTools.BuildArguments(part, defaultType, defaultValueType);
string[] partArgumentsLines = partArguments.SplitNewLines();
string group = part.Group;
if (!string.IsNullOrEmpty(group))
Expand Down
53 changes: 8 additions & 45 deletions VisualCard/Parts/CardBuilderTools.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,71 +29,34 @@ namespace VisualCard.Parts
{
internal static class CardBuilderTools
{
internal static string BuildArguments(BaseCardPartInfo partInfo, Version cardVersion, string defaultType, string defaultValue)
internal static string BuildArguments(BaseCardPartInfo partInfo, string defaultType, string defaultValue)
{
string extraKeyName =
(partInfo is XNameInfo xName ? xName.XKeyName :
partInfo is ExtraInfo exName ? exName.KeyName : "") ?? "";
return BuildArguments(partInfo.ElementTypes, partInfo.ValueType, partInfo.AltId, partInfo.Arguments, extraKeyName, cardVersion, defaultType, defaultValue);
return BuildArguments(partInfo.ElementTypes, partInfo.ValueType, partInfo.Arguments, extraKeyName, defaultType, defaultValue);
}

internal static string BuildArguments<TValue>(CardValueInfo<TValue> partInfo, Version cardVersion, string defaultType, string defaultValue) =>
BuildArguments(partInfo.ElementTypes, partInfo.ValueType, partInfo.AltId, partInfo.Arguments, "", cardVersion, defaultType, defaultValue);
internal static string BuildArguments<TValue>(CardValueInfo<TValue> partInfo, string defaultType, string defaultValue) =>
BuildArguments(partInfo.ElementTypes, partInfo.ValueType, partInfo.Arguments, "", defaultType, defaultValue);

internal static string BuildArguments(string[] elementTypes, string valueType, int altId, ArgumentInfo[] arguments, string extraKeyName, Version cardVersion, string defaultType, string defaultValue)
internal static string BuildArguments(string[] elementTypes, string valueType, ArgumentInfo[] arguments, string extraKeyName, string defaultType, string defaultValue)
{
// Filter the list of types and values first
string[] finalElementTypes = elementTypes.Where((type) => !type.Equals(defaultType, StringComparison.OrdinalIgnoreCase)).ToArray();
string finalValue = valueType.Equals(defaultValue, StringComparison.OrdinalIgnoreCase) ? "" : valueType;

// Check to see if we've been provided arguments
bool installAltId = altId >= 0 && arguments.Length > 0 && cardVersion.Major >= 4;
bool noSemicolon = altId < 0 && arguments.Length == 0 && finalElementTypes.Length == 0 && string.IsNullOrEmpty(finalValue);
bool noSemicolon = arguments.Length == 0 && finalElementTypes.Length == 0 && string.IsNullOrEmpty(finalValue);
if (noSemicolon)
return extraKeyName + VcardConstants._argumentDelimiter.ToString();

// Now, initialize the argument builder
StringBuilder argumentsBuilder = new(extraKeyName + VcardConstants._fieldDelimiter.ToString());
bool installArguments = arguments.Length > 0;
bool installElementTypes = finalElementTypes.Length > 0;
bool installValueType = !string.IsNullOrEmpty(finalValue);
bool goOn = true;

// First, install the AltId parameter if it exists
if (installAltId)
{
argumentsBuilder.Append(VcardConstants._altIdArgumentSpecifier + altId);
noSemicolon = !installArguments && !installElementTypes && !installValueType;
if (noSemicolon)
goOn = false;
else
argumentsBuilder.Append(VcardConstants._fieldDelimiter.ToString());
}

// Then, install the element types parameter if it exists
if (installElementTypes && goOn)
{
argumentsBuilder.Append(VcardConstants._typeArgumentSpecifier + string.Join(",", finalElementTypes));
noSemicolon = !installArguments && !installValueType;
if (noSemicolon)
goOn = false;
else
argumentsBuilder.Append(VcardConstants._fieldDelimiter.ToString());
}

// Then, install the value type parameter if it exists
if (installValueType && goOn)
{
argumentsBuilder.Append(VcardConstants._valueArgumentSpecifier + string.Join(",", finalValue));
noSemicolon = !installArguments;
if (noSemicolon)
goOn = false;
else
argumentsBuilder.Append(VcardConstants._fieldDelimiter.ToString());
}

// Finally, install the remaining arguments if they exist and contain keys and values
if (installArguments && goOn)
// Install the remaining arguments if they exist and contain keys and values
if (installArguments)
{
List<string> finalArguments = [];
foreach (var arg in arguments)
Expand Down

0 comments on commit 2b92059

Please sign in to comment.