diff --git a/Px.Utils.UnitTests/ModelBuilderTests/ValueParserUtilitiesTests/StringToDimensionTypeTests.cs b/Px.Utils.UnitTests/ModelBuilderTests/ValueParserUtilitiesTests/StringToDimensionTypeTests.cs
index c059b6d..85b97de 100644
--- a/Px.Utils.UnitTests/ModelBuilderTests/ValueParserUtilitiesTests/StringToDimensionTypeTests.cs
+++ b/Px.Utils.UnitTests/ModelBuilderTests/ValueParserUtilitiesTests/StringToDimensionTypeTests.cs
@@ -1,7 +1,9 @@
-using Px.Utils.ModelBuilders;
+using Px.Utils.ModelBuilders;
using Px.Utils.Models.Metadata.Enums;
+using Px.Utils.PxFile;
+using System.Globalization;
-namespace ModelBuilderTests.ValueParserUtilitiesTests
+namespace Px.Utils.UnitTests.ModelBuilderTests.ValueParserUtilitiesTests
{
[TestClass]
public class StringToDimensionTypeTests
@@ -16,14 +18,27 @@ public void TimeTest()
}
[TestMethod]
- public void ContentTest()
+ public void ContentsTest()
{
- string input = "Content";
+ string input = "Contents";
DimensionType expected = DimensionType.Content;
DimensionType actual = ValueParserUtilities.StringToDimensionType(input);
Assert.AreEqual(expected, actual);
}
+ [TestMethod]
+ [DataRow("RANKING", DimensionType.Ordinal)]
+ [DataRow("region", DimensionType.Geographical)]
+ public void CustomAliasTest(string alias, DimensionType expected)
+ {
+ string input = alias.ToUpper(CultureInfo.InvariantCulture); // Testing case-insensitivity
+ PxFileConfiguration conf = PxFileConfiguration.Default;
+ conf.Tokens.VariableTypes.Mappings[alias] = expected;
+
+ DimensionType actual = ValueParserUtilities.StringToDimensionType(input, conf);
+ Assert.AreEqual(expected, actual);
+ }
+
[TestMethod]
public void DefaultValueTest()
{
diff --git a/Px.Utils.UnitTests/Validation/ContentValidationTests/ContentValidationTests.cs b/Px.Utils.UnitTests/Validation/ContentValidationTests/ContentValidationTests.cs
index c3b3218..3fcc692 100644
--- a/Px.Utils.UnitTests/Validation/ContentValidationTests/ContentValidationTests.cs
+++ b/Px.Utils.UnitTests/Validation/ContentValidationTests/ContentValidationTests.cs
@@ -2,8 +2,11 @@
using Px.Utils.Validation;
using Px.Utils.Validation.ContentValidation;
using Px.Utils.Validation.SyntaxValidation;
+using Px.Utils.PxFile;
+using Px.Utils.Models.Metadata.Enums;
using System.Text;
using System.Reflection;
+using System.Globalization;
namespace Px.Utils.UnitTests.Validation.ContentValidationTests
{
@@ -536,6 +539,60 @@ public void ValidateValueTypesCalledWithStructuredEntryArrayWithWrongValuesRetur
}
}
+ [TestMethod]
+ [DataRow("ranking", DimensionType.Ordinal)]
+ [DataRow("REGION", DimensionType.Geographical)]
+ public void ValidateValueContentsCalledWithCustomDimensionTypesValueReturnsWithoutFeedback(string alias, DimensionType dimensionType)
+ {
+ // Arrange
+ PxFileConfiguration conf = PxFileConfiguration.Default;
+ conf.Tokens.VariableTypes.Mappings[alias] = dimensionType;
+
+ ValidationStructuredEntry entry = new(
+ filename,
+ new ValidationStructuredEntryKey("VARIABLE-TYPE", "fi", "foo"),
+ alias.ToUpper(CultureInfo.InvariantCulture), // The value is converted to upper case to verify case insensitivity of the dimension type matching
+ 0,
+ [],
+ 0,
+ Utils.Validation.ValueType.StringValue);
+
+ ContentValidator validator = new(filename, encoding, [entry], conf: conf);
+
+ // Act
+ ValidationFeedback? result = ContentValidator.ValidateValueContents(entry, validator);
+
+ // Assert
+ Assert.IsNull(result);
+ }
+
+ [TestMethod]
+ public void ValidateValueContentsCalledWithUnknownDimensionTypeValueReturnsWithError()
+ {
+ // Arrange
+ PxFileConfiguration conf = PxFileConfiguration.Default;
+
+ ValidationStructuredEntry entry = new(
+ filename,
+ new ValidationStructuredEntryKey("VARIABLE-TYPE", "fi", "foo"),
+ "Ranking",
+ 0,
+ [],
+ 0,
+ Utils.Validation.ValueType.StringValue);
+
+ ContentValidator validator = new(filename, encoding, [entry], conf: conf);
+
+ // Act
+ ValidationFeedback? result = ContentValidator.ValidateValueContents(entry, validator);
+
+ // Assert
+ Assert.IsNotNull(result);
+ Assert.HasCount(1, result);
+ Assert.AreEqual(ValidationFeedbackRule.InvalidValueFound, result.First().Key.Rule);
+ Assert.AreEqual(ValidationFeedbackLevel.Error, result.First().Key.Level);
+ }
+
[TestMethod]
public void ValidateValueAmountsCalledWithUnmatchingAmountOfElementsReturnsWithError()
{
diff --git a/Px.Utils.UnitTests/Validation/DatabaseValidation/DatabaseValidatorTests.cs b/Px.Utils.UnitTests/Validation/DatabaseValidation/DatabaseValidatorTests.cs
index f9657cf..4b6e292 100644
--- a/Px.Utils.UnitTests/Validation/DatabaseValidation/DatabaseValidatorTests.cs
+++ b/Px.Utils.UnitTests/Validation/DatabaseValidation/DatabaseValidatorTests.cs
@@ -161,7 +161,7 @@ public async Task ValidateDatabasAsynceWithCustomFunctionsReturnsFeedback()
IDatabaseValidator[] customValidators =
[
new MockCustomDatabaseValidator()
- ];
+ ];
DatabaseValidator validator = new(
"database_invalid",
customPxFileValidators: customValidators,
diff --git a/Px.Utils.UnitTests/Validation/Fixtures/ContentValidationFixtures.cs b/Px.Utils.UnitTests/Validation/Fixtures/ContentValidationFixtures.cs
index 67d3652..eada5c9 100644
--- a/Px.Utils.UnitTests/Validation/Fixtures/ContentValidationFixtures.cs
+++ b/Px.Utils.UnitTests/Validation/Fixtures/ContentValidationFixtures.cs
@@ -306,7 +306,7 @@ internal static class ContentValidationFixtures
private static readonly ValidationStructuredEntry variableTypeBarEntry =
new(filename,
new ValidationStructuredEntryKey("VARIABLE-TYPE", null, "bar"),
- "Content",
+ "Contents",
23,
[],
13,
diff --git a/Px.Utils.UnitTests/Validation/Fixtures/PxFileFixtures.cs b/Px.Utils.UnitTests/Validation/Fixtures/PxFileFixtures.cs
index 542a449..d28536e 100644
--- a/Px.Utils.UnitTests/Validation/Fixtures/PxFileFixtures.cs
+++ b/Px.Utils.UnitTests/Validation/Fixtures/PxFileFixtures.cs
@@ -1,4 +1,4 @@
-namespace Px.Utils.UnitTests.Validation.Fixtures
+namespace Px.Utils.UnitTests.Validation.Fixtures
{
internal static class PxFileFixtures
{
@@ -22,7 +22,7 @@ internal static class PxFileFixtures
"\r\nCODES(\"Vuosi\")=\"2015\",\"2016\",\"2017\",\"2018\",\"2019\",\"2020\",\"2021\",\"2022\",\"2023\",\"2024\";" +
"\r\nCODES(\"Tiedot\")=\"code-foo-val-a\",\"code-foo-val-b\";" +
"\r\nVARIABLE-TYPE(\"Vuosi\")=\"Time\";" +
- "\r\nVARIABLE-TYPE(\"Tiedot\")=\"Content\";" +
+ "\r\nVARIABLE-TYPE(\"Tiedot\")=\"Contents\";" +
"\r\nPRECISION(\"Tiedot\",\"foo-val-a\")=1;" +
"\r\nPRECISION(\"Tiedot\",\"foo-val-b\")=1;" +
"\r\nLAST-UPDATED(\"Tiedot\",\"foo-val-a\")=\"20231101 08:00\";" +
@@ -64,7 +64,7 @@ internal static class PxFileFixtures
"\r\nCODES(\"Vuosi\")=\"2015\",\"2016\",\"2017\",\"2018\",\"2019\",\"2020\",\"2021\",\"2022\",\"2023\",\"2024\";" +
"\r\nCODES(\"Tiedot\")=\"code-foo-val-a\",\"code-foo-val-b\";" +
"\r\nVARIABLE-TYPE(\"Vuosi\")=\"Time\";" +
- "\r\nVARIABLE-TYPE(\"Tiedot\")=\"Content\";" +
+ "\r\nVARIABLE-TYPE(\"Tiedot\")=\"Contents\";" +
"\r\nPRECISION(\"Tiedot\",\"foo-val-a\")=1;" +
"\r\nPRECISION(\"Tiedot\",\"foo-val-b\")=1;" +
"\r\nLAST-UPDATED(\"Tiedot\",\"foo-val-a\")=\"20231101 08:00\";" +
@@ -94,7 +94,7 @@ internal static class PxFileFixtures
"\r\nCODES(\"Vuosi\")=\"2015\",\"2016\",\"2017\",\"2018\",\"2019\",\"2020\",\"2021\",\"2022\",\"2023\",\"2024\";" +
"\r\nCODES(\"Tiedot\")=\"code-foo-val-a\",\"code-foo-val-b\";" +
"\r\nVARIABLE-TYPE(\"Vuosi\")=\"Time\";" +
- "\r\nVARIABLE-TYPE(\"Tiedot\")=\"Content\";" +
+ "\r\nVARIABLE-TYPE(\"Tiedot\")=\"Contents\";" +
"\r\nPRECISION(\"Tiedot\",\"foo-val-a\")=1;" +
"\r\nPRECISION(\"Tiedot\",\"foo-val-b\")=1;" +
"\r\nLAST-UPDATED(\"Tiedot\",\"foo-val-a\")=\"20231101 08:00\";" +
@@ -135,7 +135,7 @@ internal static class PxFileFixtures
"\r\nCODES(\"Vuosi\")=\"2015\",\"2016\",\"2017\",\"2018\",\"2019\",\"2020\",\"2021\",\"2022\",\"2023\",\"2024\";" +
"\r\nCODES(\"Tiedot\")=\"code-foo-val-a\",\"code-foo-val-b\";" +
"\r\nVARIABLE-TYPE(\"Vuosi\")=\"Time\";" +
- "\r\nVARIABLE-TYPE(\"Tiedot\")=\"Content\";" +
+ "\r\nVARIABLE-TYPE(\"Tiedot\")=\"Contents\";" +
"\r\nPRECISION(\"Tiedot\",\"foo-val-a\")=1;" +
"\r\nLAST-UPDATED(\"Tiedot\",\"foo-val-a\")=\"20231101 08:00\";" +
"\r\nUNITS(\"Tiedot\",\"foo-val-a\")=\"kpl\";" +
diff --git a/Px.Utils.sln b/Px.Utils.sln
index 4fe9d1a..9196bd0 100644
--- a/Px.Utils.sln
+++ b/Px.Utils.sln
@@ -36,6 +36,18 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Px.Utils.TestingApp", "Px.U
{D94934AF-6B41-4C66-818A-C4C33230E9DD} = {D94934AF-6B41-4C66-818A-C4C33230E9DD}
EndProjectSection
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "architecture", "architecture", "{BFA8E05B-EBD8-4085-B765-EAED69DD0874}"
+ ProjectSection(SolutionItems) = preProject
+ docs\architecture.md = docs\architecture.md
+ docs\architecture.models.md = docs\architecture.models.md
+ docs\architecture.operations.md = docs\architecture.operations.md
+ docs\architecture.overview.md = docs\architecture.overview.md
+ docs\architecture.readers.md = docs\architecture.readers.md
+ docs\architecture.serializers.md = docs\architecture.serializers.md
+ docs\architecture.testing.md = docs\architecture.testing.md
+ docs\architecture.validation.md = docs\architecture.validation.md
+ EndProjectSection
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -60,6 +72,7 @@ Global
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{EB4119B8-8292-418A-9CD3-2905DA67B889} = {BC1C9772-9B8F-49A7-A8F3-09E3A94789ED}
+ {BFA8E05B-EBD8-4085-B765-EAED69DD0874} = {42DFE3AF-7507-415A-806B-99B74519BF97}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {B1F81A3B-9FF5-4557-8A5A-A9519C42C2B2}
diff --git a/Px.Utils/ModelBuilders/ValueParserUtilities.cs b/Px.Utils/ModelBuilders/ValueParserUtilities.cs
index 33cbe84..8ff707e 100644
--- a/Px.Utils/ModelBuilders/ValueParserUtilities.cs
+++ b/Px.Utils/ModelBuilders/ValueParserUtilities.cs
@@ -1,6 +1,7 @@
-using Px.Utils.Models.Metadata.Enums;
+using Px.Utils.Models.Metadata.Enums;
using Px.Utils.Models.Metadata.ExtensionMethods;
using Px.Utils.PxFile;
+using System.Globalization;
namespace Px.Utils.ModelBuilders
{
@@ -102,6 +103,7 @@ public static string GetTimeValValueRangeString(string input, PxFileConfiguratio
///
/// Parses a string into a enumeration value.
/// This method maps the input string to a enumeration value based on the provided or default PxFileConfiguration configuration.
+ /// Mapping is done using the configured variable type mappings.
/// If the input string does not map to a known , the method returns .
///
/// The string to parse into a enumeration value.
@@ -110,20 +112,14 @@ public static string GetTimeValValueRangeString(string input, PxFileConfiguratio
public static DimensionType StringToDimensionType(string input, PxFileConfiguration? conf = null)
{
conf ??= PxFileConfiguration.Default;
- Dictionary map = new()
- {
- {conf.Tokens.VariableTypes.Content, DimensionType.Content},
- {conf.Tokens.VariableTypes.Time, DimensionType.Time},
- {conf.Tokens.VariableTypes.Ordinal, DimensionType.Ordinal},
- {conf.Tokens.VariableTypes.Nominal, DimensionType.Nominal},
- {conf.Tokens.VariableTypes.Geographical, DimensionType.Geographical},
- {conf.Tokens.VariableTypes.Other, DimensionType.Other},
- {conf.Tokens.VariableTypes.Unknown, DimensionType.Unknown}
- };
string cleanString = input.CleanStringDelimeters(conf.Symbols.Value.StringDelimeter);
- if (map.TryGetValue(cleanString, out DimensionType value)) return value;
- else return DimensionType.Unknown;
+ if (conf.Tokens.VariableTypes.Mappings.TryGetValue(cleanString, out DimensionType value))
+ {
+ return value;
+ }
+
+ return DimensionType.Unknown;
}
}
}
diff --git a/Px.Utils/Px.Utils.csproj b/Px.Utils/Px.Utils.csproj
index bd2ca8d..2e85547 100644
--- a/Px.Utils/Px.Utils.csproj
+++ b/Px.Utils/Px.Utils.csproj
@@ -2,7 +2,7 @@
Px.Utils
- 1.4.1
+ 1.5.0
net10.0
enable
enable
diff --git a/Px.Utils/PxFile/PxFileConfiguration.cs b/Px.Utils/PxFile/PxFileConfiguration.cs
index f1cbf89..9b4f2f6 100644
--- a/Px.Utils/PxFile/PxFileConfiguration.cs
+++ b/Px.Utils/PxFile/PxFileConfiguration.cs
@@ -1,4 +1,4 @@
-using Px.Utils.Models.Metadata.Enums;
+using Px.Utils.Models.Metadata.Enums;
namespace Px.Utils.PxFile
{
@@ -107,28 +107,29 @@ private TimeValue() { }
public static TimeValue DefaultTimeValue => new();
}
+ ///
+ /// Defines accepted tokens for parsing and validating dimension types using an expandable dictionary string to .
+ ///
public class VariableTypeTokens
{
- private const string CONTENT = "Content";
- private const string TIME = "Time";
- private const string ORDINAL = "Ordinal";
- private const string NOMINAL = "Nominal";
- private const string GEOGRAPHICAL = "Geographical";
- private const string OTHER = "Other";
- private const string UNKNOWN = "Unknown";
- private const string CLASSIFICATORY = "Classificatory";
-
- public string Content { get; set; } = CONTENT;
- public string Time { get; set; } = TIME;
- public string Ordinal { get; set; } = ORDINAL;
- public string Nominal { get; set; } = NOMINAL;
- public string Geographical { get; set; } = GEOGRAPHICAL;
- public string Other { get; set; } = OTHER;
- public string Unknown { get; set; } = UNKNOWN;
- public string Classificatory { get; set; } = CLASSIFICATORY;
+ ///
+ /// Gets or sets the expandable dictionary mapping string tokens to dimension types.
+ ///
+ public Dictionary Mappings { get; set; } = new(StringComparer.OrdinalIgnoreCase)
+ {
+ { "Time", DimensionType.Time },
+ { "Contents", DimensionType.Content },
+ { "Geographical", DimensionType.Geographical },
+ { "Ordinal", DimensionType.Ordinal },
+ { "Nominal", DimensionType.Nominal },
+ { "Other", DimensionType.Other },
+ };
private VariableTypeTokens() { }
+ ///
+ /// Gets the default variable type tokens configuration.
+ ///
public static VariableTypeTokens DefaultVariableTypeTokens => new();
}
diff --git a/Px.Utils/Validation/ContentValidation/ContentValidator.ValidationEntryFunctions.cs b/Px.Utils/Validation/ContentValidation/ContentValidator.ValidationEntryFunctions.cs
index 0de2425..5f0ab0a 100644
--- a/Px.Utils/Validation/ContentValidation/ContentValidator.ValidationEntryFunctions.cs
+++ b/Px.Utils/Validation/ContentValidation/ContentValidator.ValidationEntryFunctions.cs
@@ -1,4 +1,5 @@
using Px.Utils.Validation.SyntaxValidation;
+using Px.Utils.Models.Metadata.Enums;
using System.Globalization;
namespace Px.Utils.Validation.ContentValidation
@@ -317,71 +318,78 @@ public sealed partial class ContentValidator
///
/// Entry in the Px file metadata. Represented by a object
/// object that stores information that is gathered during the validation process
- /// Key value pair containing information about the rule violation is returned if an unexpected value is detected
+ /// Key value pair containing information about the rule violation is returned if an unexpected value is detected from the entry
public static ValidationFeedback? ValidateValueContents(ValidationStructuredEntry entry, ContentValidator validator)
{
- string[] allowedCharsets = ["ANSI", "Unicode"];
-
- string[] dimensionTypes = [
- validator.Conf.Tokens.VariableTypes.Content,
- validator.Conf.Tokens.VariableTypes.Time,
- validator.Conf.Tokens.VariableTypes.Geographical,
- validator.Conf.Tokens.VariableTypes.Ordinal,
- validator.Conf.Tokens.VariableTypes.Nominal,
- validator.Conf.Tokens.VariableTypes.Other,
- validator.Conf.Tokens.VariableTypes.Unknown,
- validator.Conf.Tokens.VariableTypes.Classificatory
- ];
-
+ string[] allowedValueContents = [];
+ StringComparer comparer = StringComparer.Ordinal;
+ string keyword = entry.Key.Keyword;
string value = SyntaxValidationUtilityMethods.CleanString(entry.Value, validator.Conf);
- if ((entry.Key.Keyword == validator.Conf.Tokens.KeyWords.Charset && !allowedCharsets.Contains(value)) ||
- (entry.Key.Keyword == validator.Conf.Tokens.KeyWords.CodePage && !value.Equals(validator._encoding.BodyName, StringComparison.OrdinalIgnoreCase)) ||
- (entry.Key.Keyword == validator.Conf.Tokens.KeyWords.DimensionType && !dimensionTypes.Contains(value)))
- {
- KeyValuePair feedbackIndexes = SyntaxValidationUtilityMethods.GetLineAndCharacterIndex(
- entry.KeyStartLineIndex,
- entry.ValueStartIndex,
- entry.LineChangeIndexes);
- KeyValuePair feedback = new(
- new(ValidationFeedbackLevel.Error,
- ValidationFeedbackRule.InvalidValueFound),
- new(validator._filename,
- feedbackIndexes.Key,
- feedbackIndexes.Value,
- $"{entry.Key.Keyword}: {entry.Value}")
- );
+ if (keyword == validator.Conf.Tokens.KeyWords.Charset)
+ {
+ allowedValueContents = ["ANSI", "Unicode"];
+ }
+ else if (keyword == validator.Conf.Tokens.KeyWords.CodePage)
+ {
+ allowedValueContents = [validator._encoding.BodyName];
+ comparer = StringComparer.OrdinalIgnoreCase;
+ }
+ else if (keyword == validator.Conf.Tokens.KeyWords.DimensionType)
+ {
+ if (validator.Conf.Tokens.VariableTypes.Mappings.TryGetValue(value, out DimensionType _))
+ {
+ return null;
+ }
- return new(feedback);
+ return CreateInvalidValueFeedback(entry, validator);
}
- else if (entry.Key.Keyword == validator.Conf.Tokens.KeyWords.ContentVariableIdentifier)
+ else if (keyword == validator.Conf.Tokens.KeyWords.ContentVariableIdentifier)
{
string defaultLanguage = validator._defaultLanguage ?? string.Empty;
string lang = entry.Key.Language ?? defaultLanguage;
- if (validator._stubDimensionNames is not null && validator._stubDimensionNames.TryGetValue(lang, out string[]? stubValues) &&
- !Array.Exists(stubValues, d => d == value) &&
- (validator._headingDimensionNames is not null && validator._headingDimensionNames.TryGetValue(lang, out string[]? headingValues) &&
- !Array.Exists(headingValues, d => d == value)))
- {
- KeyValuePair feedbackIndexes = SyntaxValidationUtilityMethods.GetLineAndCharacterIndex(
- entry.KeyStartLineIndex,
- entry.ValueStartIndex,
- entry.LineChangeIndexes);
+ List dimensionNames = [];
- KeyValuePair feedback = new(
- new(ValidationFeedbackLevel.Error,
- ValidationFeedbackRule.InvalidValueFound),
- new(validator._filename,
- feedbackIndexes.Key,
- feedbackIndexes.Value,
- $"{entry.Key.Keyword}: {entry.Value}")
- );
+ if (validator._stubDimensionNames is not null && validator._stubDimensionNames.TryGetValue(lang, out string[]? stubValues))
+ {
+ dimensionNames.AddRange(stubValues);
+ }
- return new(feedback);
+ if (validator._headingDimensionNames is not null && validator._headingDimensionNames.TryGetValue(lang, out string[]? headingValues))
+ {
+ dimensionNames.AddRange(headingValues);
}
+
+ allowedValueContents = [.. dimensionNames];
}
- return null;
+ if (allowedValueContents.Length == 0 || allowedValueContents.Contains(value, comparer))
+ {
+ return null;
+ }
+
+ return CreateInvalidValueFeedback(entry, validator);
+ }
+
+ private static ValidationFeedback CreateInvalidValueFeedback(
+ ValidationStructuredEntry entry,
+ ContentValidator validator)
+ {
+ KeyValuePair feedbackIndexes = SyntaxValidationUtilityMethods.GetLineAndCharacterIndex(
+ entry.KeyStartLineIndex,
+ entry.ValueStartIndex,
+ entry.LineChangeIndexes);
+
+ KeyValuePair feedback = new(
+ new(ValidationFeedbackLevel.Error,
+ ValidationFeedbackRule.InvalidValueFound),
+ new(validator._filename,
+ feedbackIndexes.Key,
+ feedbackIndexes.Value,
+ $"{entry.Key.Keyword}: {entry.Value}")
+ );
+
+ return new(feedback);
}
///
diff --git a/docs/PXFILE_SPECIFICATION.md b/docs/PXFILE_SPECIFICATION.md
index ac5ecb0..8c3d0a6 100644
--- a/docs/PXFILE_SPECIFICATION.md
+++ b/docs/PXFILE_SPECIFICATION.md
@@ -96,7 +96,7 @@ Whitespace characters are not significant in the value outside of ```"``` separa
- Decimal separator is period ```.```.
- Thousands separator is not allowed.
- Whitespace characters are not allowed between the characters of the number.
-- Number must be in range of ±7.9228 x 10^28.
+- Number must be in range of ±7.9228 x 10^28.
#### List of strings
- List items are separated by a comma ```,```.
@@ -281,6 +281,7 @@ More spesific encoding information. The value must be a string that matches the
- Recommended that the variable type is defined for each variable defined by the STUB or HEADING.
- Has a set of allowed values: ```Content```, ```Time```, ```Geographical```, ```Ordinal```, ```Nominal```, ```Other```, ```Classificatory```., ```Unknown```.
- Can be defined for each language, but this is not recommended.
+- Value is not case sensitive, but uppercase characters are recommended.
#### TIMEVAL
- See the TIMEVAL entry for the syntax and content requirements.
\ No newline at end of file
diff --git a/docs/architecture.models.md b/docs/architecture.models.md
index 7705f8c..d83ff08 100644
--- a/docs/architecture.models.md
+++ b/docs/architecture.models.md
@@ -62,6 +62,8 @@ Task BuildAsync(IAsyncEnumerable> m
Helpers: `MetadataEntryKeyBuilder`, `ValueParserUtilities`, `MetadataEntryKey`.
+`PxFileConfiguration.TokenDefinitions.VariableTypeTokens` exposes a configurable `Dictionary` (`Mappings`) used by both parsing and validation for `VARIABLE-TYPE` values. The dictionary uses `StringComparer.OrdinalIgnoreCase`, so lookups are case-insensitive by default. Custom aliases can be added by inserting additional keys into `Mappings`.
+
## Extension Methods
| File | Purpose |
diff --git a/docs/architecture.overview.md b/docs/architecture.overview.md
index 3940ea1..152f4c2 100644
--- a/docs/architecture.overview.md
+++ b/docs/architecture.overview.md
@@ -27,6 +27,7 @@ No DI container — all types instantiated directly via constructors. Configurat
| `Symbols.KeywordSeparator` | Keyword = value separator | `=` |
| `Symbols.EntrySeparator` | Entry separator | `;` |
| `Tokens.KeyWords.Data` | Data section keyword | `DATA` |
+| `Tokens.VariableTypes.Mappings` | `VARIABLE-TYPE` token to `DimensionType` mapping | Case-insensitive dictionary (`StringComparer.OrdinalIgnoreCase`) |
## Key Patterns
diff --git a/docs/architecture.validation.md b/docs/architecture.validation.md
index 1873220..84736d0 100644
--- a/docs/architecture.validation.md
+++ b/docs/architecture.validation.md
@@ -34,6 +34,8 @@ Validates metadata content (required keys, language definitions, dimension consi
File: `Validation/ContentValidation/ContentValidator.cs`
Partial files: `ValidationEntryFunctions.cs`, `ValidationFindKeywordFunctions.cs`, `UtilityMethods.cs`
+Dimension type validation uses `PxFileConfiguration.TokenDefinitions.VariableTypeTokens`. The first configured token for each dimension type is treated as the recommended primary value, while additional configured tokens are accepted as aliases and reported as warnings.
+
### DataValidator
Validates data section (row counts, row lengths, value types, separators).