diff --git a/Directory.Build.props b/Directory.Build.props
index a1904d6..fa81925 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -10,6 +10,9 @@
Michał Bryłka, Leszek Kowalski
MIT OR Apache-2.0
Copyright (c) Michał Bryłka. Icon by http://www.iconka.com
+ false
+ true
+ https://github.com/nemesissoft/Nemesis.TextParsers
true
diff --git a/Nemesis.TextParsers.CodeGen.Tests/ApprovalTests/AutoDeconstructableGeneratorApprovalTests.cs b/Nemesis.TextParsers.CodeGen.Tests/ApprovalTests/AutoDeconstructableGeneratorApprovalTests.cs
index 98178af..fd9f9c6 100644
--- a/Nemesis.TextParsers.CodeGen.Tests/ApprovalTests/AutoDeconstructableGeneratorApprovalTests.cs
+++ b/Nemesis.TextParsers.CodeGen.Tests/ApprovalTests/AutoDeconstructableGeneratorApprovalTests.cs
@@ -15,17 +15,17 @@ namespace Nemesis.TextParsers.CodeGen.Tests.ApprovalTests
internal class AutoDeconstructableGeneratorApprovalTests
{
[Test] public void ApprovalTestsRecord() => RunCase("Record");
-
+
[Test] public void ApprovalTestsStruct() => RunCase("ReadOnlyStruct");
-
+
[Test] public void ApprovalTestsLarge() => RunCase("Large");
-
+
[Test] public void ApprovalTestsComplexTypes() => RunCase("ComplexType");
-
+
[Test] public void ApprovalTestsSimpleWrapperStruct() => RunCase("SimpleWrapperStruct");
-
-
+
+
[Test]
public void HouseKeeping() => ApprovalMaintenance.VerifyNoAbandonedFiles();
@@ -34,11 +34,11 @@ private static void RunCase(string index)
var (_, source, _) = EndToEndCases.AutoDeconstructableCases().SingleOrDefault(t => t.name == index);
Assert.That(source, Is.Not.Null);
Assert.That(source, Is.Not.Empty);
-
+
var compilation = CreateCompilation(
$@"using Nemesis.TextParsers.Settings; namespace Nemesis.TextParsers.CodeGen.Tests {{ {source} }}");
- var generatedTrees = AutoDeconstructableGeneratorTests.GetGeneratedTreesOnly(compilation);
+ var generatedTrees = GetGeneratedTreesOnly(compilation);
var actual = ScrubGeneratorComments(generatedTrees.Single());
diff --git a/Nemesis.TextParsers.CodeGen.Tests/AutoDeconstructableGeneratorTests.cs b/Nemesis.TextParsers.CodeGen.Tests/AutoDeconstructableGeneratorTests.cs
index c1d9edd..fea66dc 100644
--- a/Nemesis.TextParsers.CodeGen.Tests/AutoDeconstructableGeneratorTests.cs
+++ b/Nemesis.TextParsers.CodeGen.Tests/AutoDeconstructableGeneratorTests.cs
@@ -1,45 +1,38 @@
extern alias original;
-using System;
using System.Collections.Generic;
using System.Linq;
-using Microsoft.CodeAnalysis;
-using Microsoft.CodeAnalysis.CSharp.Syntax;
-using Nemesis.CodeAnalysis;
-using Nemesis.TextParsers.CodeGen.Deconstructable;
-
using NUnit.Framework;
using static Nemesis.TextParsers.CodeGen.Tests.Utils;
+namespace Nemesis.TextParsers.CodeGen.Tests;
-namespace Nemesis.TextParsers.CodeGen.Tests
+[TestFixture]
+public partial class AutoDeconstructableGeneratorTests
{
- [TestFixture]
- public partial class AutoDeconstructableGeneratorTests
- {
- private static readonly IEnumerable _endToEndCases = EndToEndCases.AutoDeconstructableCases()
- .Select((t, i) => new TestCaseData($@"
+ private static readonly IEnumerable _endToEndCases = EndToEndCases.AutoDeconstructableCases()
+ .Select((t, i) => new TestCaseData($@"
using Nemesis.TextParsers.Settings;
namespace Nemesis.TextParsers.CodeGen.Tests {{ {t.source} }}", t.expectedCode)
- .SetName($"E2E_{i + 1:00}_{t.name}"));
+ .SetName($"E2E_{i + 1:00}_{t.name}"));
- [TestCaseSource(nameof(_endToEndCases))]
- public void EndToEndTests(string source, string expectedCode)
- {
- var compilation = CreateCompilation(source);
+ [TestCaseSource(nameof(_endToEndCases))]
+ public void EndToEndTests(string source, string expectedCode)
+ {
+ var compilation = CreateCompilation(source);
- var generatedTrees = GetGeneratedTreesOnly(compilation);
+ var generatedTrees = GetGeneratedTreesOnly(compilation);
- var actual = ScrubGeneratorComments(generatedTrees.Single());
+ var actual = ScrubGeneratorComments(generatedTrees.Single());
- Assert.That(actual, Is.EqualTo(expectedCode).Using(IgnoreNewLinesComparer.EqualityComparer));
- }
+ Assert.That(actual, Is.EqualTo(expectedCode).Using(IgnoreNewLinesComparer.EqualityComparer));
+ }
- private static readonly IEnumerable _settingsCases = new (string typeDefinition, string expectedCodePart)[]
- {
- (@"[DeconstructableSettings(':', '␀', '/', '{', '}')]
+ private static readonly IEnumerable _settingsCases = new (string typeDefinition, string expectedCodePart)[]
+ {
+ (@"[DeconstructableSettings(':', '␀', '/', '{', '}')]
readonly partial struct Child
{
public byte Age { get; }
@@ -49,87 +42,59 @@ readonly partial struct Child
}", "private readonly TupleHelper _helper = new TupleHelper(':', '␀', '/', '{', '}');"),
- (@"[DeconstructableSettings('_', '␀', '*', '<', '>')]
+ (@"[DeconstructableSettings('_', '␀', '*', '<', '>')]
partial record T(byte B) { }", @"new TupleHelper('_', '␀', '*', '<', '>');"),
- (@"[DeconstructableSettings('_', '␀', '*', '<')]
+ (@"[DeconstructableSettings('_', '␀', '*', '<')]
partial record T(byte B) { }", @"new TupleHelper('_', '␀', '*', '<', ')');"),
- (@"[DeconstructableSettings('_', '␀', '*')]
+ (@"[DeconstructableSettings('_', '␀', '*')]
partial record T(byte B) { }", @"new TupleHelper('_', '␀', '*', '(', ')');"),
- (@"[DeconstructableSettings('_', '␀')]
+ (@"[DeconstructableSettings('_', '␀')]
partial record T(byte B) { }", @"new TupleHelper('_', '␀', '\\', '(', ')');"),
- (@"[DeconstructableSettings('_')]
+ (@"[DeconstructableSettings('_')]
partial record T(byte B) { }", @"new TupleHelper('_', '∅', '\\', '(', ')');"),
- (@"[DeconstructableSettings]
+ (@"[DeconstructableSettings]
partial record T(byte B) { }", @"new TupleHelper(';', '∅', '\\', '(', ')');"),
- (@"partial record T(byte B) { }", @"_helper = transformerStore.SettingsStore.GetSettingsFor().ToTupleHelper();"),
+ (@"partial record T(byte B) { }", @"_helper = transformerStore.SettingsStore.GetSettingsFor().ToTupleHelper();"),
- (@"[DeconstructableSettings(useDeconstructableEmpty: true)]
+ (@"[DeconstructableSettings(useDeconstructableEmpty: true)]
partial record T(byte B) { }", @"public override T GetEmpty() => new T(_transformer_B.GetEmpty());"),
- (@"[DeconstructableSettings(useDeconstructableEmpty: false)]
+ (@"[DeconstructableSettings(useDeconstructableEmpty: false)]
partial record T(byte B) { }", @"NOT CONTAIN:GetEmpty()"),
- }
- .Select((t, i) => new TestCaseData($@"using Nemesis.TextParsers.Settings; namespace Tests {{ [Auto.AutoDeconstructable] {t.typeDefinition} }}", t.expectedCodePart)
- .SetName($"Settings{i + 1:00}"));
-
- [TestCaseSource(nameof(_settingsCases))]
- public void SettingsRetrieval_ShouldEmitProperValues(string source, string expectedCodePart)
- {
- bool matchNotContain = expectedCodePart.StartsWith("NOT CONTAIN:");
- if (matchNotContain)
- expectedCodePart = expectedCodePart.Substring(12);
-
- //arrange
- var compilation = CreateCompilation(source);
-
- //act
- var generatedTrees = GetGeneratedTreesOnly(compilation);
- var actual = generatedTrees.Single();
+ }
+ .Select((t, i) => new TestCaseData($@"using Nemesis.TextParsers.Settings; namespace Tests {{ [Auto.AutoDeconstructable] {t.typeDefinition} }}", t.expectedCodePart)
+ .SetName($"Settings{i + 1:00}"));
+ [TestCaseSource(nameof(_settingsCases))]
+ public void SettingsRetrieval_ShouldEmitProperValues(string source, string expectedCodePart)
+ {
+ bool matchNotContain = expectedCodePart.StartsWith("NOT CONTAIN:");
+ if (matchNotContain)
+ expectedCodePart = expectedCodePart.Substring(12);
- //assert
- Assert.That(actual, matchNotContain ? Does.Not.Contain(expectedCodePart) : Does.Contain(expectedCodePart));
- }
+ //arrange
+ var compilation = CreateCompilation(source);
- public static IReadOnlyList GetGeneratedTreesOnly(Compilation compilation, int requiredCardinality = 1)
- {
- var newComp = CompilationUtils.RunGenerators(compilation, out var diagnostics, new AutoDeconstructableGenerator());
- Assert.That(diagnostics, Is.Empty);
-
- SyntaxTree attributeTree = null;
- foreach (var tree in newComp.SyntaxTrees)
- {
- var attributeDeclaration = tree.GetRoot().DescendantNodes().OfType()
- .FirstOrDefault(cds => string.Equals(cds.Identifier.ValueText, AutoDeconstructableGenerator.ATTRIBUTE_NAME, StringComparison.Ordinal));
- if (attributeDeclaration != null)
- {
- attributeTree = tree;
- break;
- }
- }
- Assert.That(attributeTree, Is.Not.Null, "Auto attribute not found among generated trees");
+ //act
+ var generatedTrees = GetGeneratedTreesOnly(compilation);
+ var actual = generatedTrees.Single();
- var toRemove = compilation.SyntaxTrees.Append(attributeTree);
- var generatedTrees = newComp.RemoveSyntaxTrees(toRemove).SyntaxTrees.ToList();
- Assert.That(generatedTrees, Has.Count.EqualTo(requiredCardinality));
-
- return generatedTrees.Select(tree =>
- ((CompilationUnitSyntax)tree.GetRoot())
- .ToFullString()).ToList();
- }
+ //assert
+ Assert.That(actual, matchNotContain ? Does.Not.Contain(expectedCodePart) : Does.Contain(expectedCodePart));
+ }
- [Test]
- public void Generate_When_StaticUsing_And_Mnemonics()
- {
- var compilation = CreateCompilation(@"using SD = System.Double;
+ [Test]
+ public void Generate_When_StaticUsing_And_Mnemonics()
+ {
+ var compilation = CreateCompilation(@"using SD = System.Double;
using static Tests3.ContainerClass3;
namespace Tests1
@@ -148,11 +113,11 @@ namespace Tests3
public static class ContainerClass3 { public class NestedClass3 { } }
}");
- var generatedTrees = GetGeneratedTreesOnly(compilation);
+ var generatedTrees = GetGeneratedTreesOnly(compilation);
- var actual = ScrubGeneratorComments(generatedTrees.Single());
+ var actual = ScrubGeneratorComments(generatedTrees.Single());
- Assert.That(actual, Is.EqualTo(@"//HEAD
+ Assert.That(actual, Is.EqualTo(@"//HEAD
using System;
using Nemesis.TextParsers;
using Nemesis.TextParsers.Parsers;
@@ -235,7 +200,6 @@ public override string Format(Numbers element)
}
}
}").Using(IgnoreNewLinesComparer.EqualityComparer));
- }
}
}
diff --git a/Nemesis.TextParsers.CodeGen.Tests/GlobalSuppressions.cs b/Nemesis.TextParsers.CodeGen.Tests/GlobalSuppressions.cs
new file mode 100644
index 0000000..1c0bb7f
--- /dev/null
+++ b/Nemesis.TextParsers.CodeGen.Tests/GlobalSuppressions.cs
@@ -0,0 +1,8 @@
+// This file is used by Code Analysis to maintain SuppressMessage
+// attributes that are applied to this project.
+// Project-level suppressions either have no target or are given
+// a specific target and scoped to a namespace, type, member, etc.
+
+using System.Diagnostics.CodeAnalysis;
+
+[assembly: SuppressMessage("Style", "IDE0057:Use range operator", Justification = "Multiple target frameworks without support for range operator", Scope = "namespaceanddescendants", Target = "~N:Nemesis.TextParsers.CodeGen.Tests")]
diff --git a/Nemesis.TextParsers.CodeGen.Tests/Nemesis.TextParsers.CodeGen.Tests.csproj b/Nemesis.TextParsers.CodeGen.Tests/Nemesis.TextParsers.CodeGen.Tests.csproj
index 4970acc..df92887 100644
--- a/Nemesis.TextParsers.CodeGen.Tests/Nemesis.TextParsers.CodeGen.Tests.csproj
+++ b/Nemesis.TextParsers.CodeGen.Tests/Nemesis.TextParsers.CodeGen.Tests.csproj
@@ -3,8 +3,7 @@
net6.0
true
- $(NoWarn);NU1603
- false
+ $(NoWarn);NU1603
diff --git a/Nemesis.TextParsers.CodeGen.Tests/Utils.cs b/Nemesis.TextParsers.CodeGen.Tests/Utils.cs
index df60fa5..ca8466a 100644
--- a/Nemesis.TextParsers.CodeGen.Tests/Utils.cs
+++ b/Nemesis.TextParsers.CodeGen.Tests/Utils.cs
@@ -1,58 +1,89 @@
extern alias original;
using System;
using System.Collections.Generic;
+using System.Linq;
using System.Numerics;
using System.Reflection;
using System.Text.RegularExpressions;
using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
using Nemesis.CodeAnalysis;
+using Nemesis.TextParsers.CodeGen.Deconstructable;
+using NUnit.Framework;
-namespace Nemesis.TextParsers.CodeGen.Tests
+namespace Nemesis.TextParsers.CodeGen.Tests;
+
+internal static class Utils
{
- internal static class Utils
+ public static Compilation CreateCompilation(string source, OutputKind outputKind = OutputKind.DynamicallyLinkedLibrary)
{
- public static Compilation CreateCompilation(string source, OutputKind outputKind = OutputKind.DynamicallyLinkedLibrary)
- {
- var (compilation, _, _) = CompilationUtils.CreateTestCompilation(source, new[]
- {
- typeof(BigInteger).GetTypeInfo().Assembly,
- typeof(original::Nemesis.TextParsers.ITransformer).GetTypeInfo().Assembly
- }, outputKind);
+ var (compilation, _, _) = CompilationUtils.CreateTestCompilation(source, new[]
+ {
+ typeof(BigInteger).GetTypeInfo().Assembly,
+ typeof(original::Nemesis.TextParsers.ITransformer).GetTypeInfo().Assembly
+ }, outputKind);
- return compilation;
- }
+ return compilation;
+ }
- private static readonly Regex _headerPattern = new(@"/\*\s* .+? \s*\*/", RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.CultureInvariant | RegexOptions.IgnorePatternWhitespace | RegexOptions.Compiled);
- private static readonly Regex _generatorPattern = new(@""".*Generator""\s*,\s*""([0-9.]+)""", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant | RegexOptions.IgnorePatternWhitespace | RegexOptions.Compiled);
+ private static readonly Regex _headerPattern = new(@"/\*\s* .+? \s*\*/", RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.CultureInvariant | RegexOptions.IgnorePatternWhitespace | RegexOptions.Compiled);
+ private static readonly Regex _generatorPattern = new(@""".*Generator""\s*,\s*""([0-9.]+)""", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant | RegexOptions.IgnorePatternWhitespace | RegexOptions.Compiled);
- public static string ScrubGeneratorComments(string text)
- {
- text = _generatorPattern.Replace(text, "string.Empty, string.Empty");
- text = _headerPattern.Replace(text, "//HEAD");
+ public static string ScrubGeneratorComments(string text)
+ {
+ text = _generatorPattern.Replace(text, "string.Empty, string.Empty");
+ text = _headerPattern.Replace(text, "//HEAD");
+
+ return text;
+ }
+
+ public static IReadOnlyList GetGeneratedTreesOnly(Compilation compilation, int requiredCardinality = 1)
+ {
+ var newComp = CompilationUtils.RunGenerators(compilation, out var diagnostics, new AutoDeconstructableGenerator());
+ Assert.That(diagnostics, Is.Empty);
- return text;
+ SyntaxTree attributeTree = null;
+ foreach (var tree in newComp.SyntaxTrees)
+ {
+ var attributeDeclaration = tree.GetRoot().DescendantNodes().OfType()
+ .FirstOrDefault(cds => string.Equals(cds.Identifier.ValueText, AutoDeconstructableGenerator.ATTRIBUTE_NAME, StringComparison.Ordinal));
+ if (attributeDeclaration != null)
+ {
+ attributeTree = tree;
+ break;
+ }
}
+ Assert.That(attributeTree, Is.Not.Null, "Auto attribute not found among generated trees");
+
+ var toRemove = compilation.SyntaxTrees.Append(attributeTree);
+
+ var generatedTrees = newComp.RemoveSyntaxTrees(toRemove).SyntaxTrees.ToList();
+ Assert.That(generatedTrees, Has.Count.EqualTo(requiredCardinality));
+
+ return generatedTrees.Select(tree =>
+ ((CompilationUnitSyntax)tree.GetRoot())
+ .ToFullString()).ToList();
}
+}
- internal class IgnoreNewLinesComparer : IComparer, IEqualityComparer
- {
- public static readonly IComparer Comparer = new IgnoreNewLinesComparer();
+internal class IgnoreNewLinesComparer : IComparer, IEqualityComparer
+{
+ public static readonly IComparer Comparer = new IgnoreNewLinesComparer();
- public static readonly IEqualityComparer EqualityComparer = new IgnoreNewLinesComparer();
+ public static readonly IEqualityComparer EqualityComparer = new IgnoreNewLinesComparer();
- public int Compare(string x, string y) => string.CompareOrdinal(NormalizeNewLines(x), NormalizeNewLines(y));
+ public int Compare(string x, string y) => string.CompareOrdinal(NormalizeNewLines(x), NormalizeNewLines(y));
- public bool Equals(string x, string y) => NormalizeNewLines(x) == NormalizeNewLines(y);
+ public bool Equals(string x, string y) => NormalizeNewLines(x) == NormalizeNewLines(y);
- public int GetHashCode(string s) => NormalizeNewLines(s)?.GetHashCode() ?? 0;
+ public int GetHashCode(string s) => NormalizeNewLines(s)?.GetHashCode() ?? 0;
- public static string NormalizeNewLines(string s) => s?
- .Replace(Environment.NewLine, "")
- .Replace("\n", "")
- .Replace("\r", "");
- }
+ public static string NormalizeNewLines(string s) => s?
+ .Replace(Environment.NewLine, "")
+ .Replace("\n", "")
+ .Replace("\r", "");
}
diff --git a/Nemesis.TextParsers.CodeGen/Nemesis.TextParsers.CodeGen.csproj b/Nemesis.TextParsers.CodeGen/Nemesis.TextParsers.CodeGen.csproj
index 5ccfd6e..931c062 100644
--- a/Nemesis.TextParsers.CodeGen/Nemesis.TextParsers.CodeGen.csproj
+++ b/Nemesis.TextParsers.CodeGen/Nemesis.TextParsers.CodeGen.csproj
@@ -2,11 +2,10 @@
netstandard2.0
-
-
+ true
$(PackageIdPrefix)$(AssemblyName)
codegen codegeneration generation trnasformer parse ReadOnlySpan Span Memory fast allocation noAllocation
Contains various parser optimized for speed and no allocation
@@ -19,9 +18,7 @@
true
- review-icon.png
- true
- https://github.com/nemesissoft/Nemesis.TextParsers
+ review-icon.png
$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb
true
diff --git a/Nemesis.TextParsers.Tests/RecordsTests.cs b/Nemesis.TextParsers.Tests/RecordsTests.cs
index 8fbdf40..f1a5b68 100644
--- a/Nemesis.TextParsers.Tests/RecordsTests.cs
+++ b/Nemesis.TextParsers.Tests/RecordsTests.cs
@@ -45,10 +45,13 @@ public void ShouldBeAbleToReparseComplexRecords()
Assert.That(formatted, Is.EqualTo("(Mike;36;(Comodo Dragon)|(Lizard))"));
var parsed = sut.Parse(formatted);
- Assert.That(parsed.Name, Is.EqualTo("Mike"));
- Assert.That(parsed.Age, Is.EqualTo(36));
- Assert.That(parsed.Animals[0].Name, Is.EqualTo("Comodo Dragon"));
- Assert.That(parsed.Animals[1].Name, Is.EqualTo("Lizard"));
+ Assert.Multiple(() =>
+ {
+ Assert.That(parsed.Name, Is.EqualTo("Mike"));
+ Assert.That(parsed.Age, Is.EqualTo(36));
+ Assert.That(parsed.Animals[0].Name, Is.EqualTo("Comodo Dragon"));
+ Assert.That(parsed.Animals[1].Name, Is.EqualTo("Lizard"));
+ });
}
enum Habitat { Terrestrial/*, Aquatic, Amphibian*/ }
@@ -85,11 +88,14 @@ public void ShouldBeAbleToReparse()
Assert.That(formatted, Is.EqualTo(@"Janusz-Korwin\-Mikke-78"));
var parsed = sut.Parse(formatted);
- Assert.That(parsed.FirstName, Is.EqualTo("Janusz"));
- Assert.That(parsed.FamilyName, Is.EqualTo("Korwin-Mikke"));
- Assert.That(parsed.Age, Is.EqualTo(78));
+ Assert.Multiple(() =>
+ {
+ Assert.That(parsed.FirstName, Is.EqualTo("Janusz"));
+ Assert.That(parsed.FamilyName, Is.EqualTo("Korwin-Mikke"));
+ Assert.That(parsed.Age, Is.EqualTo(78));
- Assert.That(parsed, Is.EqualTo(politician));
+ Assert.That(parsed, Is.EqualTo(politician));
+ });
}
[Transformer(typeof(PersonTransformer))]
@@ -120,11 +126,12 @@ public void ShouldBeAbleToReparse(string input, double expectedFirst, double exp
var sut = Sut.GetTransformer>();
var parsed = sut.Parse(input);
- Assert.That(parsed?.First ?? double.NaN, Is.EqualTo(expectedFirst));
- Assert.That(parsed?.Second ?? double.NaN, Is.EqualTo(expectedSecond));
- Assert.That(parsed?.Third ?? double.NaN, Is.EqualTo(expectedThird));
-
-
+ Assert.Multiple(() =>
+ {
+ Assert.That(parsed?.First ?? double.NaN, Is.EqualTo(expectedFirst));
+ Assert.That(parsed?.Second ?? double.NaN, Is.EqualTo(expectedSecond));
+ Assert.That(parsed?.Third ?? double.NaN, Is.EqualTo(expectedThird));
+ });
var formatted = sut.Format(parsed);
var parsed2 = sut.Parse(formatted);
Assert.That(parsed, Is.EqualTo(parsed2));
diff --git a/Nemesis.TextParsers/Nemesis.TextParsers.csproj b/Nemesis.TextParsers/Nemesis.TextParsers.csproj
index 83f7fc9..1c5d3e4 100644
--- a/Nemesis.TextParsers/Nemesis.TextParsers.csproj
+++ b/Nemesis.TextParsers/Nemesis.TextParsers.csproj
@@ -3,18 +3,17 @@
net7.0;net6.0;netcoreapp3.1;netstandard2.1;netstandard2.0
split stringSplit tokenize token parse format list dictionary TextConverter ReadOnlySpan Span Memory fast allocation noAllocation
- Contains various parser optimized for speed and no allocation
-
+ Contains various parser optimized for speed and no allocation.
- $(PackageIdPrefix)$(AssemblyName)
- review-icon.png
- true
- https://github.com/nemesissoft/Nemesis.TextParsers
+ true
+ $(PackageIdPrefix)$(AssemblyName)
+ properties\review-icon.png
+ properties\README.md
+
RELEASE_NOTES_PLACEHOLDER
-
$(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb
true
true
@@ -22,7 +21,13 @@
-
+
+ Properties\icon.png
+
+
+
+ Properties\README.md
+
@@ -59,10 +64,5 @@
<_Parameter1>$(MSBuildProjectName).Tests, PublicKey=00240000048000001a010000060200000024000052534131300800000100010035c8d69e21b106b1164c8fc9c108ed2c08b283d13af6028fc6d6dd07ddd98039bcd99689793df5eef77230ce0a469dfb3ba7575ec699a6e001224ef90b3ce3437e873f0e5bc267a992a78ce1ecb85545d021f17ce51dccf9b3b2cb418aa9adcd2cf93fcc53ab12cb80a5cd51dcf6f3f3be70777b5dbf6d43dc20801be7f9d8220d8ac1082391647e650ff596673c8cd40257f113c8d59f8b150cebc991eeedc69a9c1d442f93089a276aad3122cf90feafb02a384524fcab4d269de23aa5666c6fcc8b89766455d8e0fe9e65d1034673382c596cc60ee8d1b1b4fedb767ff05d7d6cdae0c0db091c24311ae373f98887826256298d72a772a3a8abee357a28f6a5bb4f4369ab
-
-
-
-
+
\ No newline at end of file
diff --git a/Nemesis.TextParsers/Parsers/03_SimpleTypes.cs b/Nemesis.TextParsers/Parsers/03_SimpleTypes.cs
index 339add3..ad148f9 100644
--- a/Nemesis.TextParsers/Parsers/03_SimpleTypes.cs
+++ b/Nemesis.TextParsers/Parsers/03_SimpleTypes.cs
@@ -878,7 +878,7 @@ protected override Regex ParseCore(in ReadOnlySpan input)
_helper.ParseEnd(ref enumerator, 2, TYPE_NAME);
- return new Regex(pattern, options);
+ return new(pattern, options);
}
public override string Format(Regex re)
@@ -907,7 +907,9 @@ public override string Format(Regex re)
private RegexTransformer() { }
+#pragma warning disable SYSLIB1045 // Convert to 'GeneratedRegexAttribute'.
public override Regex GetEmpty() => new("", RegexOptions.None);
+#pragma warning restore SYSLIB1045 // Convert to 'GeneratedRegexAttribute'.
}
internal class RegexOptionsTransformer : TransformerBase
diff --git a/README.md b/README.md
index 30edc81..7ceda10 100644
--- a/README.md
+++ b/README.md
@@ -40,7 +40,7 @@ TL;DR - are you looking for performant, non allocating serializer from structura
### Other popular choices
-When stucked with a task of parsing various items form strings we ofter opt for TypeConverter (https://docs.microsoft.com/en-us/dotnet/api/system.componentmodel.typeconverter) ? We tend to create methods like:
+When stucked with a task of parsing various items form strings we often opt for TypeConverter (https://docs.microsoft.com/en-us/dotnet/api/system.componentmodel.typeconverter) ? We tend to create methods like:
```csharp
public static T FromString(string text) =>
(T)TypeDescriptor.GetConverter(typeof(T))
@@ -143,9 +143,7 @@ Open source software is free but creating it is not. Should you wish to support
* [![Donate using Liberapay](https://liberapay.com/assets/widgets/donate.svg)](https://liberapay.com/Michal.Brylka/donate) ![Liberapay receiving](https://img.shields.io/liberapay/receives/Michal.Brylka?color=blue&style=flat-square)
-
## Todo / road map
- [ ] ability to format to buffer i.e. TryFormat pattern
-- [x] become more DI friendly adding support for cross cutting concerns i.e. logging and own TransformerStore customizations
- [ ] support for ILookup<,>, IGrouping<,>, ReadOnlyObservableCollection<>
- [ ] support for native parsing/formatting of F# types (map, collections, records...)
diff --git a/Specification.md b/Specification.md
index a4028dc..ca7482e 100644
--- a/Specification.md
+++ b/Specification.md
@@ -55,7 +55,8 @@ Generally, not affected by custom settings, parsed using InvariantCulture. The f
* RegexOptions.IgnorePatternWhitespace → 'x'
* RegexOptions.RightToLeft → 'r'
* RegexOptions.ECMAScript → 'e'
- * RegexOptions.CultureInvariant → 'v'
+ * RegexOptions.CultureInvariant → 'v'
+ * RegexOptions.NonBacktracking → 'b'
### KeyValuePair<,> (compound parser)
@@ -72,7 +73,7 @@ While generally possible, one might be tempted to format/parse octuples and larg
Format can be customized using settings
### Transformables aspect
-User can register his own transformer. More on this topic in **Transformables** section below.
+User can register his own transformer. More on this topic in [Transformables](#transformables) section below.
### FactoryMethod
(legacy) It is possible to use type's ```ToString``` method for formatting and static ```FromText(ReadOnlySpan text)``` or ```FromText(string text)``` method for parsing. If given entity's code is not owned at parsing point, it's possible to provide separate FactoryMethod transformer
@@ -106,7 +107,7 @@ Generally parsed as separated with '|' and optionally enclosed in brackets/brace
Format can be customized using settings - separately for arrays and other collections.
### Deconstructables aspect
-Values can be formatted automatically using deconstructor and parsed using matching constructor's metadata. More on this topic in **Deconstructables** section below. Format can be customized using settings.
+Values can be formatted automatically using deconstructor and parsed using matching constructor's metadata. More on this topic in [Deconstructables](#deconstructables) section below. Format can be customized using settings.
### TypeConverters (for legacy reasons)
@@ -135,7 +136,8 @@ internal class CustomList : ICustomList, IEquatable : TransformerBase>
{
- //4. Transformable aspect supports simple injection of ITransformerStore via it's constructor - user can use other transformers already registered for simple/complex types
+ //4. Transformable aspect supports simple injection of ITransformerStore via it's constructor
+ // User can thus use other transformers already registered for simple/complex types
private readonly ITransformerStore _transformerStore;
public CustomListTransformer(ITransformerStore transformerStore) => _transformerStore = transformerStore;
@@ -149,7 +151,6 @@ internal class CustomListTransformer : TransformerBase
}
```
+Since records contain appropriate constructor/deconstructor, one can use [Deconstructables](#deconstructables) aspect on them.
+
Finally, you can implement own _`Nemesis.TextParsers.ITransformer`_ or (if you really have no other option) _`System.ComponentModel.TypeConverter`_ class
## C# 9.0 Code generation
With introduction of new code-gen engine, you can opt to have your transformer generated automatically without any imperative code.
```csharp
+// add to csproj
+
//1. use specially provided (via code-gen) Auto.AutoDeconstructable attribute
[Auto.AutoDeconstructable]
//2. provide deconstructable aspect options or leave this attribute out - default options will be engaged
[DeconstructableSettings('_', '∅', '%', '〈', '〉')]
-readonly partial /*3. partial modifier is VERY important - you need this cause generated code is placed in different file*/ struct StructPoint3d
+readonly
+partial //3. partial modifier is VERY important - you need this cause generated code is placed in different file
+struct StructPoint3d
{
public double X { get; }
public double Y { get; }