mirror of
https://github.com/claunia/SabreTools.git
synced 2025-12-16 19:14:27 +00:00
Clean up filter code; detuple
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using SabreTools.Core.Tools;
|
||||
using SabreTools.Models.Metadata;
|
||||
|
||||
@@ -8,36 +7,6 @@ namespace SabreTools.Core.Filter
|
||||
{
|
||||
public static class FieldManipulator
|
||||
{
|
||||
/// <summary>
|
||||
/// Regex pattern to match scene dates
|
||||
/// </summary>
|
||||
private const string _sceneDateRegex = @"([0-9]{2}\.[0-9]{2}\.[0-9]{2}-)(.*?-.*?)";
|
||||
|
||||
/// <summary>
|
||||
/// Replace the machine name with the description
|
||||
/// </summary>
|
||||
/// <returns>Original machine name on success, null on error</returns>
|
||||
public static string? DescriptionToName(Machine? machine)
|
||||
{
|
||||
// If the machine is missing, we can't do anything
|
||||
if (machine == null)
|
||||
return null;
|
||||
|
||||
// Get both the current name and description
|
||||
string? name = machine.ReadString(Header.NameKey);
|
||||
string? description = machine.ReadString(Header.DescriptionKey);
|
||||
|
||||
// Sanitize the description string
|
||||
description = description?
|
||||
.Replace('/', '_')
|
||||
.Replace("\"", "''")
|
||||
.Replace(":", " -");
|
||||
|
||||
// Replace the name with the description
|
||||
machine[Header.NameKey] = description;
|
||||
return name;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove a field from a given DictionaryBase
|
||||
/// </summary>
|
||||
@@ -96,27 +65,5 @@ namespace SabreTools.Core.Filter
|
||||
dictionaryBase[fieldName!] = value;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Strip the dates from the beginning of scene-style machine name and description
|
||||
/// </summary>
|
||||
public static bool StripSceneDates(Machine? machine)
|
||||
{
|
||||
// If the machine is missing, we can't do anything
|
||||
if (machine == null)
|
||||
return false;
|
||||
|
||||
// Strip dates from the name field
|
||||
string? name = machine.ReadString(Header.NameKey);
|
||||
if (name != null && Regex.IsMatch(name, _sceneDateRegex))
|
||||
machine[Header.NameKey] = Regex.Replace(name, _sceneDateRegex, @"$2");
|
||||
|
||||
// Strip dates from the description field
|
||||
string? description = machine.ReadString(Header.DescriptionKey);
|
||||
if (description != null && Regex.IsMatch(description, _sceneDateRegex))
|
||||
machine[Header.DescriptionKey] = Regex.Replace(description, _sceneDateRegex, @"$2");
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,26 +14,24 @@ namespace SabreTools.Core.Filter
|
||||
/// <summary>
|
||||
/// Key name for the filter
|
||||
/// </summary>
|
||||
public string[] Key { get; }
|
||||
public readonly string[] Key;
|
||||
|
||||
/// <summary>
|
||||
/// Value to match in the filter
|
||||
/// </summary>
|
||||
public string? Value { get; }
|
||||
public readonly string? Value;
|
||||
|
||||
/// <summary>
|
||||
/// Operation on how to match the filter
|
||||
/// </summary>
|
||||
public Operation Operation { get; }
|
||||
public readonly Operation Operation;
|
||||
|
||||
public FilterObject(string filterString)
|
||||
{
|
||||
(string? keyItem, Operation operation, string? value) = SplitFilterString(filterString);
|
||||
if (keyItem == null)
|
||||
if (!SplitFilterString(filterString, out var keyItem, out Operation operation, out var value))
|
||||
throw new ArgumentOutOfRangeException(nameof(filterString));
|
||||
|
||||
(string? itemName, string? fieldName) = FilterParser.ParseFilterId(keyItem);
|
||||
if (itemName == null || fieldName == null)
|
||||
if (!FilterParser.ParseFilterId(keyItem, out var itemName, out var fieldName))
|
||||
throw new ArgumentOutOfRangeException(nameof(filterString));
|
||||
|
||||
Key = [itemName, fieldName];
|
||||
@@ -43,8 +41,7 @@ namespace SabreTools.Core.Filter
|
||||
|
||||
public FilterObject(string itemField, string? value, string? operation)
|
||||
{
|
||||
(string? itemName, string? fieldName) = FilterParser.ParseFilterId(itemField);
|
||||
if (itemName == null || fieldName == null)
|
||||
if (!FilterParser.ParseFilterId(itemField, out var itemName, out var fieldName))
|
||||
throw new ArgumentOutOfRangeException(nameof(value));
|
||||
|
||||
Key = [itemName, fieldName];
|
||||
@@ -54,11 +51,10 @@ namespace SabreTools.Core.Filter
|
||||
|
||||
public FilterObject(string itemField, string? value, Operation operation)
|
||||
{
|
||||
(string? itemName, string? fieldName) = FilterParser.ParseFilterId(itemField);
|
||||
if (itemName == null || fieldName == null)
|
||||
if (!FilterParser.ParseFilterId(itemField, out var itemName, out var fieldName))
|
||||
throw new ArgumentOutOfRangeException(nameof(value));
|
||||
|
||||
Key = [itemName, fieldName];
|
||||
Key = [itemName!, fieldName!];
|
||||
Value = value;
|
||||
Operation = operation;
|
||||
}
|
||||
@@ -396,10 +392,13 @@ namespace SabreTools.Core.Filter
|
||||
/// <summary>
|
||||
/// Derive a key, operation, and value from the input string, if possible
|
||||
/// </summary>
|
||||
private static (string?, Operation, string?) SplitFilterString(string? filterString)
|
||||
private static bool SplitFilterString(string? filterString, out string? key, out Operation operation, out string? value)
|
||||
{
|
||||
// Set default values
|
||||
key = null; operation = Operation.NONE; value = null;
|
||||
|
||||
if (filterString == null)
|
||||
return (null, Operation.NONE, null);
|
||||
return false;
|
||||
|
||||
// Trim quotations, if necessary
|
||||
if (filterString.StartsWith("\""))
|
||||
@@ -408,13 +407,13 @@ namespace SabreTools.Core.Filter
|
||||
// Split the string using regex
|
||||
var match = Regex.Match(filterString, @"^(?<itemField>[a-zA-Z.]+)(?<operation>[=!:><]{1,2})(?<value>.*)$");
|
||||
if (!match.Success)
|
||||
return (null, Operation.NONE, null);
|
||||
return false;
|
||||
|
||||
string itemField = match.Groups["itemField"].Value;
|
||||
Operation operation = GetOperation(match.Groups["operation"].Value);
|
||||
string value = match.Groups["value"].Value;
|
||||
key = match.Groups["itemField"].Value;
|
||||
operation = GetOperation(match.Groups["operation"].Value);
|
||||
value = match.Groups["value"].Value;
|
||||
|
||||
return (itemField, operation, value);
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -10,125 +10,166 @@ namespace SabreTools.Core.Filter
|
||||
/// <summary>
|
||||
/// Parse a filter ID string into the item name and field name, if possible
|
||||
/// </summary>
|
||||
public static (string?, string?) ParseFilterId(string itemFieldString)
|
||||
public static bool ParseFilterId(string? itemFieldString, out string itemName, out string fieldName)
|
||||
{
|
||||
// Set default values
|
||||
itemName = string.Empty; fieldName = string.Empty;
|
||||
|
||||
// If we don't have a filter ID, we can't do anything
|
||||
if (string.IsNullOrEmpty(itemFieldString))
|
||||
return (null, null);
|
||||
if (itemFieldString == null)
|
||||
return false;
|
||||
|
||||
// If we only have one part, we can't do anything
|
||||
string[] splitFilter = itemFieldString.Split('.');
|
||||
if (splitFilter.Length != 2)
|
||||
return (null, null);
|
||||
return false;
|
||||
|
||||
return ParseFilterId(splitFilter[0], splitFilter[1]);
|
||||
// Set and sanitize the filter ID
|
||||
itemName = splitFilter[0];
|
||||
fieldName = splitFilter[1];
|
||||
return ParseFilterId(ref itemName, ref fieldName);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse a filter ID string into the item name and field name, if possible
|
||||
/// </summary>
|
||||
public static (string?, string?) ParseFilterId(string itemName, string? fieldName)
|
||||
public static bool ParseFilterId(ref string itemName, ref string fieldName)
|
||||
{
|
||||
// If we don't have a filter ID, we can't do anything
|
||||
if (string.IsNullOrEmpty(itemName) || string.IsNullOrEmpty(fieldName))
|
||||
return (null, null);
|
||||
return false;
|
||||
|
||||
// Return santized values based on the split ID
|
||||
return itemName.ToLowerInvariant() switch
|
||||
{
|
||||
// Header
|
||||
"header" => ParseHeaderFilterId(fieldName!),
|
||||
"header" => ParseHeaderFilterId(ref itemName, ref fieldName),
|
||||
|
||||
// Machine
|
||||
"game" => ParseMachineFilterId(fieldName!),
|
||||
"machine" => ParseMachineFilterId(fieldName!),
|
||||
"resource" => ParseMachineFilterId(fieldName!),
|
||||
"set" => ParseMachineFilterId(fieldName!),
|
||||
"game" => ParseMachineFilterId(ref itemName, ref fieldName),
|
||||
"machine" => ParseMachineFilterId(ref itemName, ref fieldName),
|
||||
"resource" => ParseMachineFilterId(ref itemName, ref fieldName),
|
||||
"set" => ParseMachineFilterId(ref itemName, ref fieldName),
|
||||
|
||||
// DatItem
|
||||
"datitem" => ParseDatItemFilterId(fieldName!),
|
||||
"item" => ParseDatItemFilterId(fieldName!),
|
||||
_ => ParseDatItemFilterId(itemName, fieldName!),
|
||||
"datitem" => ParseDatItemFilterId(ref itemName, ref fieldName),
|
||||
"item" => ParseDatItemFilterId(ref itemName, ref fieldName),
|
||||
_ => ParseDatItemFilterId(ref itemName, ref fieldName),
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse and validate header fields
|
||||
/// </summary>
|
||||
private static (string?, string?) ParseHeaderFilterId(string fieldName)
|
||||
private static bool ParseHeaderFilterId(ref string itemName, ref string fieldName)
|
||||
{
|
||||
// Get the set of constants
|
||||
var constants = TypeHelper.GetConstants(typeof(Header));
|
||||
if (constants == null)
|
||||
return (null, null);
|
||||
return false;
|
||||
|
||||
// Get if there's a match to the constant
|
||||
string? constantMatch = constants.FirstOrDefault(c => string.Equals(c, fieldName, StringComparison.OrdinalIgnoreCase));
|
||||
string localFieldName = fieldName;
|
||||
string? constantMatch = constants.FirstOrDefault(c => string.Equals(c, localFieldName, StringComparison.OrdinalIgnoreCase));
|
||||
if (constantMatch == null)
|
||||
return (null, null);
|
||||
return false;
|
||||
|
||||
// Return the sanitized ID
|
||||
return (MetadataFile.HeaderKey, constantMatch);
|
||||
itemName = MetadataFile.HeaderKey;
|
||||
fieldName = constantMatch;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse and validate machine/game fields
|
||||
/// </summary>
|
||||
private static (string?, string?) ParseMachineFilterId(string fieldName)
|
||||
private static bool ParseMachineFilterId(ref string itemName, ref string fieldName)
|
||||
{
|
||||
// Get the set of constants
|
||||
var constants = TypeHelper.GetConstants(typeof(Machine));
|
||||
if (constants == null)
|
||||
return (null, null);
|
||||
return false;
|
||||
|
||||
// Get if there's a match to the constant
|
||||
string? constantMatch = constants.FirstOrDefault(c => string.Equals(c, fieldName, StringComparison.OrdinalIgnoreCase));
|
||||
string localFieldName = fieldName;
|
||||
string? constantMatch = constants.FirstOrDefault(c => string.Equals(c, localFieldName, StringComparison.OrdinalIgnoreCase));
|
||||
if (constantMatch == null)
|
||||
return (null, null);
|
||||
return false;
|
||||
|
||||
// Return the sanitized ID
|
||||
return (MetadataFile.MachineKey, constantMatch);
|
||||
itemName = MetadataFile.MachineKey;
|
||||
fieldName = constantMatch;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse and validate item fields
|
||||
/// </summary>
|
||||
private static (string?, string?) ParseDatItemFilterId(string fieldName)
|
||||
private static bool ParseDatItemFilterId(ref string itemName, ref string fieldName)
|
||||
{
|
||||
// Get all item types
|
||||
var itemTypes = TypeHelper.GetDatItemTypeNames();
|
||||
// Special case if the item name is reserved
|
||||
if (string.Equals(itemName, "datitem", StringComparison.OrdinalIgnoreCase)
|
||||
|| string.Equals(itemName, "item", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
// Get all item types
|
||||
var itemTypes = TypeHelper.GetDatItemTypeNames();
|
||||
|
||||
// If we get any matches
|
||||
string? match = itemTypes.FirstOrDefault(t => t != null && ParseDatItemFilterId(t, fieldName) != (null, null));
|
||||
if (match != null)
|
||||
return ("item", ParseDatItemFilterId(match, fieldName).Item2);
|
||||
// If we get any matches
|
||||
string localFieldName = fieldName;
|
||||
string? matchedType = itemTypes.FirstOrDefault(t => DatItemContainsField(t, localFieldName));
|
||||
if (matchedType != null)
|
||||
{
|
||||
// Check for a matching field
|
||||
string? matchedField = GetMatchingField(matchedType, fieldName);
|
||||
if (matchedField == null)
|
||||
return false;
|
||||
|
||||
itemName = "item";
|
||||
fieldName = matchedField;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check for a matching field
|
||||
string? matchedField = GetMatchingField(itemName, fieldName);
|
||||
if (matchedField == null)
|
||||
return false;
|
||||
|
||||
itemName = itemName.ToLowerInvariant();
|
||||
fieldName = matchedField;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Nothing was found
|
||||
return (null, null);
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Parse and validate item fields
|
||||
/// Determine if an item type contains a field
|
||||
/// </summary>
|
||||
private static (string?, string?) ParseDatItemFilterId(string itemName, string fieldName)
|
||||
private static bool DatItemContainsField(string itemName, string fieldName)
|
||||
=> GetMatchingField(itemName, fieldName) != null;
|
||||
|
||||
/// <summary>
|
||||
/// Determine if an item type contains a field
|
||||
/// </summary>
|
||||
private static string? GetMatchingField(string itemName, string fieldName)
|
||||
{
|
||||
// Get the correct item type
|
||||
var itemType = TypeHelper.GetDatItemType(itemName.ToLowerInvariant());
|
||||
if (itemType == null)
|
||||
return (null, null);
|
||||
return null;
|
||||
|
||||
// Get the set of constants
|
||||
var constants = TypeHelper.GetConstants(itemType);
|
||||
if (constants == null)
|
||||
return (null, null);
|
||||
return null;
|
||||
|
||||
// Get if there's a match to the constant
|
||||
string? constantMatch = constants.FirstOrDefault(c => string.Equals(c, fieldName, StringComparison.OrdinalIgnoreCase));
|
||||
if (constantMatch == null)
|
||||
return (null, null);
|
||||
|
||||
// Return the sanitized ID
|
||||
return (itemName.ToLowerInvariant(), constantMatch);
|
||||
string localFieldName = fieldName;
|
||||
string? constantMatch = constants.FirstOrDefault(c => string.Equals(c, localFieldName, StringComparison.OrdinalIgnoreCase));
|
||||
return constantMatch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace SabreTools.Core.Filter
|
||||
if (filters == null)
|
||||
throw new ArgumentNullException(nameof(filters));
|
||||
|
||||
this.Filters = filters;
|
||||
Filters = filters;
|
||||
}
|
||||
|
||||
public FilterRunner(string[]? filterStrings)
|
||||
@@ -34,7 +34,7 @@ namespace SabreTools.Core.Filter
|
||||
filters.Add(new FilterObject(filterString));
|
||||
}
|
||||
|
||||
this.Filters = [.. filters];
|
||||
Filters = [.. filters];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -51,7 +51,7 @@ namespace SabreTools.Core.Filter
|
||||
};
|
||||
|
||||
// Loop through and run each filter in order
|
||||
foreach (var filter in this.Filters)
|
||||
foreach (var filter in Filters)
|
||||
{
|
||||
// If the filter isn't for this object type, skip
|
||||
if (filter.Key[0] != itemName)
|
||||
|
||||
@@ -42,7 +42,7 @@ namespace SabreTools.Core.Tools
|
||||
/// <summary>
|
||||
/// Attempt to get all DatItem types
|
||||
/// </summary>
|
||||
public static string?[] GetDatItemTypeNames()
|
||||
public static string[] GetDatItemTypeNames()
|
||||
{
|
||||
List<string> typeNames = [];
|
||||
|
||||
|
||||
@@ -114,8 +114,7 @@ namespace SabreTools.DatFiles
|
||||
return false;
|
||||
|
||||
// Get the parser pair out of it, if possible
|
||||
(string? type, string? key) = FilterParser.ParseFilterId(field);
|
||||
if (type == null || key == null)
|
||||
if (!FilterParser.ParseFilterId(field, out string type, out string key))
|
||||
return false;
|
||||
|
||||
switch (type)
|
||||
|
||||
@@ -68,7 +68,8 @@ namespace SabreTools.Filtering
|
||||
string fieldString = inputTrimmed.Split(':')[0].ToLowerInvariant().Trim('"', ' ', '\t');
|
||||
string fileString = inputTrimmed.Substring(fieldString.Length + 1).Trim('"', ' ', '\t');
|
||||
|
||||
item.FieldName = FilterParser.ParseFilterId(fieldString);
|
||||
FilterParser.ParseFilterId(fieldString, out string itemName, out string fieldName);
|
||||
item.FieldName = (itemName, fieldName);
|
||||
if (item.PopulateFromFile(fileString))
|
||||
Items.Add(item);
|
||||
}
|
||||
|
||||
@@ -92,8 +92,7 @@ namespace SabreTools.Filtering
|
||||
return false;
|
||||
|
||||
// Get the parser pair out of it, if possible
|
||||
(string? type, string? key) = FilterParser.ParseFilterId(field);
|
||||
if (type == null || key == null)
|
||||
if (!FilterParser.ParseFilterId(field, out string type, out string key))
|
||||
return false;
|
||||
|
||||
switch (type)
|
||||
|
||||
@@ -2023,9 +2023,13 @@ Some special strings that can be used:
|
||||
List<string> updateFields = [];
|
||||
foreach (string fieldName in GetList(features, UpdateFieldListValue))
|
||||
{
|
||||
(string? itemType, string? key) = FilterParser.ParseFilterId(fieldName);
|
||||
if (itemType == Models.Metadata.MetadataFile.MachineKey && key != null)
|
||||
updateFields.Add(key);
|
||||
// Ensure the field is valid
|
||||
if (!FilterParser.ParseFilterId(fieldName, out string itemType, out string key))
|
||||
continue;
|
||||
if (itemType != Models.Metadata.MetadataFile.MachineKey)
|
||||
continue;
|
||||
|
||||
updateFields.Add(key);
|
||||
}
|
||||
|
||||
return updateFields;
|
||||
@@ -2039,14 +2043,16 @@ Some special strings that can be used:
|
||||
Dictionary<string, List<string>> updateFields = [];
|
||||
foreach (string fieldName in GetList(features, UpdateFieldListValue))
|
||||
{
|
||||
(string? itemType, string? key) = FilterParser.ParseFilterId(fieldName);
|
||||
if (itemType != null && itemType != Models.Metadata.MetadataFile.HeaderKey && itemType != Models.Metadata.MetadataFile.MachineKey && key != null)
|
||||
{
|
||||
if (!updateFields.ContainsKey(itemType))
|
||||
updateFields[itemType] = [];
|
||||
// Ensure the field is valid
|
||||
if (!FilterParser.ParseFilterId(fieldName, out string itemType, out string key))
|
||||
continue;
|
||||
if (itemType == Models.Metadata.MetadataFile.HeaderKey || itemType == Models.Metadata.MetadataFile.MachineKey)
|
||||
continue;
|
||||
|
||||
updateFields[itemType].Add(key);
|
||||
}
|
||||
if (!updateFields.ContainsKey(itemType))
|
||||
updateFields[itemType] = [];
|
||||
|
||||
updateFields[itemType].Add(key);
|
||||
}
|
||||
|
||||
return updateFields;
|
||||
|
||||
@@ -315,11 +315,11 @@ Reset the internal state: reset();";
|
||||
}
|
||||
|
||||
// Read in the individual arguments
|
||||
(string? type, string? key) = FilterParser.ParseFilterId(Arguments[0]);
|
||||
bool parsed = FilterParser.ParseFilterId(Arguments[0], out _, out _);
|
||||
string extraFile = Arguments[1];
|
||||
|
||||
// If we had an invalid input, log and continue
|
||||
if (type == null && key == null)
|
||||
if (!parsed)
|
||||
{
|
||||
string message = $"{Arguments[0]} was an invalid field name";
|
||||
return (false, message);
|
||||
@@ -337,12 +337,12 @@ Reset the internal state: reset();";
|
||||
public override void Process(BatchState batchState)
|
||||
{
|
||||
// Read in the individual arguments
|
||||
(string?, string?) fieldName = FilterParser.ParseFilterId(Arguments[0]);
|
||||
FilterParser.ParseFilterId(Arguments[0], out string itemName, out string fieldName);
|
||||
string extraFile = Arguments[1];
|
||||
|
||||
// Create the extra INI
|
||||
var extraIni = new ExtraIni();
|
||||
var extraIniItem = new ExtraIniItem() { FieldName = fieldName };
|
||||
var extraIniItem = new ExtraIniItem() { FieldName = (itemName, fieldName) };
|
||||
extraIniItem.PopulateFromFile(extraFile);
|
||||
extraIni.Items.Add(extraIniItem);
|
||||
|
||||
@@ -376,7 +376,7 @@ Reset the internal state: reset();";
|
||||
}
|
||||
|
||||
// Read in the individual arguments
|
||||
(string? type, string? key) = FilterParser.ParseFilterId(Arguments[0]);
|
||||
bool parsed = FilterParser.ParseFilterId(Arguments[0], out _, out _);
|
||||
bool? filterRemove = false;
|
||||
if (Arguments.Count >= 3)
|
||||
filterRemove = Arguments[2].AsYesNo();
|
||||
@@ -385,7 +385,7 @@ Reset the internal state: reset();";
|
||||
filterPerMachine = Arguments[3].AsYesNo();
|
||||
|
||||
// If we had an invalid input, log and continue
|
||||
if (type == null && key == null)
|
||||
if (!parsed)
|
||||
{
|
||||
string message = $"{Arguments[0]} was an invalid field name";
|
||||
return (false, message);
|
||||
@@ -805,10 +805,10 @@ Reset the internal state: reset();";
|
||||
}
|
||||
|
||||
// Read in the individual arguments
|
||||
(string? type, string? key) = FilterParser.ParseFilterId(Arguments[0]);
|
||||
bool parsed = FilterParser.ParseFilterId(Arguments[0], out string type, out _);
|
||||
|
||||
// If we had an invalid input, log and continue
|
||||
if ((type == null || !string.Equals(type, Models.Metadata.MetadataFile.HeaderKey, StringComparison.OrdinalIgnoreCase)) && key == null)
|
||||
if (!parsed || !string.Equals(type, Models.Metadata.MetadataFile.HeaderKey, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
string message = $"{Arguments[0]} was an invalid field name";
|
||||
return (false, message);
|
||||
|
||||
Reference in New Issue
Block a user