Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
e85251f
Renamed ValidationResult to ValidationError
william-gross Mar 18, 2025
d7bbafa
Restructured underlying validation methods
william-gross Mar 19, 2025
a2cf592
Renamed validation method input parameters
william-gross Mar 19, 2025
73df1e3
Overhauled Validator.isEmpty to handle trimming
william-gross Mar 20, 2025
6edc544
Re-introduced ValidationMethod delegate
william-gross Mar 20, 2025
fa56464
Overhauled ExecuteValidation to return a result
william-gross Mar 20, 2025
2f148c2
Updated public validation methods to return result
william-gross Mar 20, 2025
b3947f7
Updated Validator usages elsewhere in TEWL
william-gross Mar 20, 2025
8764a02
Named usages of ExecuteValidation emptyValue param
william-gross Mar 20, 2025
1448204
Removed result storage from ValidationErrorHandler
william-gross Mar 20, 2025
68b95d3
Removed ValidationPackage
william-gross Mar 20, 2025
aeb765a
Removed ValidationError.NoError.
william-gross Mar 20, 2025
afe056f
Removed ErrorCondition.NoError.
william-gross Mar 20, 2025
d89ce21
Renamed ErrorCondition to ValidationErrorType
william-gross Mar 20, 2025
fa444f7
Formatted ValidationErrorHandler
william-gross Mar 20, 2025
6d24a08
Made ExecuteValidation handler parameter nullable
william-gross Mar 20, 2025
dbb5511
Made ValidationErrorHandler parameters nullable
william-gross Mar 20, 2025
fe70e4c
Documented ExecuteValidation handler parameter
william-gross Mar 20, 2025
4428eb1
Moved text validations to their own file
william-gross Mar 21, 2025
197cfab
Moved phone validations to their own file
william-gross Mar 21, 2025
2537e6f
Moved numeric validations to their own file
william-gross Mar 21, 2025
1625544
Moved boolean validations to their own file
william-gross Mar 21, 2025
f50778e
Moved ZIP code validations to their own file
william-gross Mar 21, 2025
195de52
Moved date/time validations to their own file
william-gross Mar 21, 2025
3167f84
Cleaned up Validator
william-gross Mar 21, 2025
c2f4cba
Converted Error class to a nested record
william-gross Mar 21, 2025
8987d50
Renamed GetNumber to GetNumericString
william-gross Mar 24, 2025
e2b28f1
Fixed doc typo in ValidationResult
william-gross Mar 26, 2025
c45b2f6
Merge branch 'validatorImprovements' into enduracode-main
william-gross Sep 19, 2025
fad2e43
Merge branch 'localDateTools' into enduracode-main
william-gross Sep 19, 2025
1856b0c
Merge branch 'getTextWriterForWrite-Utf8WithBom' into enduracode-main
william-gross Sep 19, 2025
195a35e
Merge branch 'durationTools' into enduracode-main
william-gross Sep 19, 2025
eb7fdb5
Merge branch 'rateLimiter' into enduracode-main
william-gross Sep 19, 2025
c30a206
Merge branch 'patternString' into enduracode-main
william-gross Sep 19, 2025
44ddfb7
Merge branch 'trustedHtmlString' into enduracode-main
william-gross Sep 19, 2025
6050a51
Merge branch 'enumToolsCleanup' into enduracode-main
william-gross Sep 19, 2025
1b10957
Merge branch 'synchronizationTools' into enduracode-main
william-gross Sep 19, 2025
61d901a
Updated to .NET 9
william-gross Oct 29, 2025
5f463f2
Migrated legacy-encoded files to UTF-8 w/BOM
william-gross Oct 29, 2025
46a74a5
Transformed old Tester into NUnit tests
william-gross Jan 1, 2026
1179ad0
Added EWL-generated MSBuild props
william-gross Jan 1, 2026
768ad92
Corrected target framework
william-gross Jan 1, 2026
f528d7a
Moved in ByteFormattingTests from EWL
william-gross Jan 1, 2026
febd268
Fixed OldTester
william-gross Jan 1, 2026
d535619
Removed output writers made obsolete by Serilog
william-gross Jan 1, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
Tewl/Directory.Build.props
Tewl/Generated Code/
Tests/Generated Code/

## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
Expand Down
2 changes: 1 addition & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<Project>
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<TargetFramework>net9.0</TargetFramework>
</PropertyGroup>
</Project>
2 changes: 2 additions & 0 deletions EWL ReSharper Settings.DotSettings
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,7 @@
<s:String x:Key="/Default/Environment/InlayHints/VBParameterNameHintsOptions/ShowParameterNameHints/@EntryValue">Never</s:String>
<s:Boolean x:Key="/Default/Environment/ParameterNameHintsOptions/ShowParameterNameHints/@EntryValue">False</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SearchAndNavigation/MergeOccurences/@EntryValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EPsiFeatures_002EVisualStudio_002EBackend_002EDaemon_002EHighlightingSettingsMigrator/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EFeature_002EServices_002ECSharp_002EParameterNameHints_002ECSharpParameterNameHintsOptionsMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EFeature_002EServices_002EVB_002EParameterNameHints_002EVBParameterNameHintsOptionsMigration/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpAttributeForSingleLineMethodUpgrade/@EntryIndexedValue">True</s:Boolean>
Expand Down Expand Up @@ -1311,6 +1312,7 @@
<s:Boolean x:Key="/Default/Housekeeping/VsActionManager/KeyboardShortcutToVsCommand/=Up/Commands/=_003Cdata_0020id_003D_0022_0028_007B1496a755_002D94de_002D11d0_002D8c3f_002D00c04fc2aae2_007D_003A11_0029_0022_0020shortcut_003D_0022Up_0022_0020_002F_003E/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Housekeeping/VsActionManager/KeyboardShortcutToVsCommand/=Up/Commands/=_003Cdata_0020id_003D_0022_0028_007B1496a755_002D94de_002D11d0_002D8c3f_002D00c04fc2aae2_007D_003A1227_0029_0022_0020shortcut_003D_0022Up_0022_0020_002F_003E/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Housekeeping/VsActionManager/KeyboardShortcutToVsCommand/=Up/Commands/=_003Cdata_0020id_003D_0022_0028_007B1496a755_002D94de_002D11d0_002D8c3f_002D00c04fc2aae2_007D_003A1502_0029_0022_0020shortcut_003D_0022Up_0022_0020_002F_003E/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/Housekeeping/VsHighlighting/SuppressVsSquiggles/@EntryValue">True</s:Boolean>
<s:String x:Key="/Default/Housekeeping/VsSavedAutocompletionValue/OverrideParameterInfo/=CSharp/@EntryIndexedValue">NotOverridden</s:String>
<s:String x:Key="/Default/Housekeeping/VsSavedAutocompletionValue/OverrideParameterInfo/=Css/@EntryIndexedValue">NotOverridden</s:String>
<s:String x:Key="/Default/Housekeeping/VsSavedAutocompletionValue/OverrideParameterInfo/=Html/@EntryIndexedValue">NotOverridden</s:String>
Expand Down
6 changes: 3 additions & 3 deletions TEWL.sln
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.29911.98
# Visual Studio Version 18
VisualStudioVersion = 18.1.11312.151 d18.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tewl", "Tewl\Tewl.csproj", "{C6158C5A-CD33-4193-80CC-A9BBD7EC60D7}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TewlTester", "TewlTester\TewlTester.csproj", "{F250853F-5A4E-46E8-BFFB-C142DBE996F6}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests", "Tests\Tests.csproj", "{F250853F-5A4E-46E8-BFFB-C142DBE996F6}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand Down
3 changes: 3 additions & 0 deletions Tests/.editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# generated by EWL
[*.cs]
csharp_default_internal_modifier = implicit
23 changes: 23 additions & 0 deletions Tests/ByteFormattingTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
namespace Tests;

class ByteFormattingTests {
[ Test ]
public void Bytes() {
Assert.That( FormattingMethods.GetFormattedBytes( 64 ), Is.EqualTo( "64 bytes" ) );
}

[ Test ]
public void Kilo() {
Assert.That( FormattingMethods.GetFormattedBytes( 64_000 ), Is.EqualTo( "62 KiB" ) );
}

[ Test ]
public void Mega() {
Assert.That( FormattingMethods.GetFormattedBytes( 64_000_000 ), Is.EqualTo( "61 MiB" ) );
}

[ Test ]
public void Giga() {
Assert.That( FormattingMethods.GetFormattedBytes( 64_500_000_000 ), Is.EqualTo( "60.1 GiB" ) );
}
}
36 changes: 36 additions & 0 deletions Tests/Directory.Build.props
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<Project>
<Import Project="$([MSBuild]::GetPathOfFileAbove('$(MSBuildThisFile)','$(MSBuildThisFileDirectory)../'))" />
<PropertyGroup>
<AssemblyName>Tests</AssemblyName>
<RootNamespace>Tests</RootNamespace>
<Version>28.0.41.0</Version>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<Product>TEWL</Product>
<AssemblyTitle>TEWL - Tests</AssemblyTitle>
<PackageVersion>0</PackageVersion>
<RuntimeIdentifier>win-x64</RuntimeIdentifier>
<CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>
<Nullable>enable</Nullable>
<CopyDebugSymbolFilesFromPackages>true</CopyDebugSymbolFilesFromPackages>
<DefaultItemExcludesInProjectFolder>$(DefaultItemExcludesInProjectFolder);Directory.Build.props;Directory.Build.targets;**/*.ewlt.cs</DefaultItemExcludesInProjectFolder>
<GarbageCollectionAdaptationMode>0</GarbageCollectionAdaptationMode>
<NuGetAuditMode>direct</NuGetAuditMode>
<IsTransformWebConfigDisabled>true</IsTransformWebConfigDisabled>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.14.1" />
<PackageReference Include="NUnit.Analyzers" Version="4.10.0">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="NUnit3TestAdapter" Version="5.2.0" />
<Using Include="System" />
<Using Include="System.Collections.Generic" />
<Using Include="System.IO" />
<Using Include="System.Linq" />
<Using Include="NUnit.Framework" />
<Using Include="Tewl" />
<Using Include="Tewl.Tools" />
<Using Include="Humanizer.StringExtensions"><Static>True</Static></Using>
</ItemGroup>
</Project>
76 changes: 76 additions & 0 deletions Tests/OldTester.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
using Tewl.IO;
using Tewl.IO.TabularDataParsing;

namespace Tests;

[ TestFixture ]
class Program {
[ Test ]
public static void OldMain() {
testExcelWriting();
testCsvWriting();
testCsv();
testTabDelimitedWriting();
testXls();
}

private static void testExcelWriting() {
var excelFile = new ExcelFileWriter();
excelFile.DefaultWorksheet.AddHeaderToWorksheet( "ID", "Name", "Date", "Email", "Website" );
excelFile.DefaultWorksheet.AddRowToWorksheet( "123", "Greg", "1/1/2012", "greg.smalter@gmail.com", "https://www.google.com" );
excelFile.DefaultWorksheet.AddRowToWorksheet( "321", "", "12/19/2020", "", "https://microsoft.com" );

using var stream = File.OpenWrite( "tewlTestTabularWrite.xlsx" );
excelFile.SaveToStream( stream );
}

private static void testCsvWriting() {
var csvFile = new CsvFileWriter();

using var stream = new StreamWriter( File.OpenWrite( "tewlTestTabularWrite.csv" ) );
writeData( csvFile, stream );
}

private static void testTabDelimitedWriting() {
var csvFile = new TabDelimitedFileWriter();

using var stream = new StreamWriter( File.OpenWrite( "tewlTestTabularWrite.txt" ) );
writeData( csvFile, stream );
}

// It's sort of a failure that the Excel writer cannot be passed here. But between there being more than one worksheet and other problems, it's hard to
// have it implement the same interface.
private static void writeData( TextBasedTabularDataFileWriter writer, TextWriter stream ) {
writer.AddValuesToLine( "ID", "Name", "Date", "Email", "Website" );
writer.WriteCurrentLineToFile( stream );
writer.AddValuesToLine( "123", "Greg", "1/1/2012", "greg.smalter@gmail.com", "https://www.google.com" );
writer.WriteCurrentLineToFile( stream );
writer.AddValuesToLine( "123", "Greg", "1/1/2012", "greg.smalter@gmail.com", "https://www.google.com" );
writer.WriteCurrentLineToFile( stream );
}

private static void testCsv() {
var csvParser = TabularDataParser.CreateForCsvFile( @"..\..\..\..\TestFiles\TewlTestBook.csv", [ ] );
var validationErrors = new List<DataValidationError>();

csvParser.ParseAndProcessAllLines( importThing, validationErrors );

Console.WriteLine( $"CSV test: {csvParser.RowsWithoutValidationErrors} rows imported without error." );
}

private static void testXls() {
var xlsParser = TabularDataParser.CreateForExcelFile( @"..\..\..\..\TestFiles\TewlTestBook.xlsx", [ ] );
var validationErrors = new List<DataValidationError>();

xlsParser.ParseAndProcessAllLines( importThing, validationErrors );

Console.WriteLine( $"Excel test: {xlsParser.RowsWithoutValidationErrors} rows imported without error." );
}

private static void importThing( ParsedLine line, Tewl.InputValidation.Validator validator ) {
var value = line[ "dATe" ];
var email = line[ "email" ];
var website = line[ "website" ];
Console.WriteLine( line.LineNumber + ": Date: " + value + $", Email: {email}, Website: {website}" );
}
}
File renamed without changes.
9 changes: 6 additions & 3 deletions TewlTester/TewlTester.csproj → Tests/Tests.csproj
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0-windows</TargetFramework>
<TargetFramework>net9.0-windows</TargetFramework>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="NUnit" Version="4.4.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Tewl\Tewl.csproj" />
</ItemGroup>
Expand Down
28 changes: 28 additions & 0 deletions Tewl/Directory.Build.props
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<Project>
<Import Project="$([MSBuild]::GetPathOfFileAbove('$(MSBuildThisFile)','$(MSBuildThisFileDirectory)../'))" />
<PropertyGroup>
<AssemblyName>Tewl</AssemblyName>
<RootNamespace>Tewl</RootNamespace>
<Version>28.0.41.0</Version>
<GenerateAssemblyCompanyAttribute>false</GenerateAssemblyCompanyAttribute>
<Product>TEWL</Product>
<AssemblyTitle>TEWL</AssemblyTitle>
<PackageVersion>0</PackageVersion>
<CheckForOverflowUnderflow>true</CheckForOverflowUnderflow>
<Nullable>enable</Nullable>
<CopyDebugSymbolFilesFromPackages>true</CopyDebugSymbolFilesFromPackages>
<DefaultItemExcludesInProjectFolder>$(DefaultItemExcludesInProjectFolder);Directory.Build.props;Directory.Build.targets;**/*.ewlt.cs</DefaultItemExcludesInProjectFolder>
<NuGetAuditMode>direct</NuGetAuditMode>
<IsTransformWebConfigDisabled>true</IsTransformWebConfigDisabled>
</PropertyGroup>
<ItemGroup>
<InternalsVisibleTo Include="Tests" />
<Using Include="System" />
<Using Include="System.Collections.Generic" />
<Using Include="System.IO" />
<Using Include="System.Linq" />
<Using Include="Tewl" />
<Using Include="Tewl.Tools" />
<Using Include="Humanizer.StringExtensions"><Static>True</Static></Using>
</ItemGroup>
</Project>
2 changes: 1 addition & 1 deletion Tewl/FormattingMethods.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;
using JetBrains.Annotations;
using Tewl.InputValidation;
using Tewl.Tools;
Expand Down
21 changes: 21 additions & 0 deletions Tewl/ICalendar/ICalendarTools.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using Ical.Net.DataTypes;
using NodaTime;

namespace Tewl.ICalendar;

/// <summary>
/// Static methods pertaining to the iCalendar format.
/// </summary>
[ PublicAPI ]
public static class ICalendarTools {
/// <summary>
/// Creates an iCalendar date/time from this ZonedDateTime.
/// </summary>
public static CalDateTime ToICalendarTime( this ZonedDateTime time ) =>
new( time.Year, time.Month, time.Day, time.Hour, time.Minute, time.Second, time.Zone.Id );

/// <summary>
/// Creates an iCalendar date from this LocalDate.
/// </summary>
public static CalDateTime ToICalendarDate( this LocalDate date ) => new( date.Year, date.Month, date.Day );
}
2 changes: 1 addition & 1 deletion Tewl/IO/CsvFileWriter.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System.IO;
using System.IO;
using JetBrains.Annotations;

namespace Tewl.IO {
Expand Down
25 changes: 10 additions & 15 deletions Tewl/IO/ExcelWorksheet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -83,31 +83,26 @@ private void addRowToWorksheet( bool bold, params string[] cellValues ) {
}

private void putRowValueInCell( IXLCell cell, string value ) {
var v = new Validator();
var detectedDate = v.GetNullableDateTime(
new ValidationErrorHandler( "" ),
value,
DateTimeTools.DayMonthYearFormats.Concat( DateTimeTools.MonthDayYearFormats ).ToArray(),
false,
DateTime.MinValue,
DateTime.MaxValue );
if( !v.ErrorsOccurred ) {
if( new Validator().GetNullableDateTime(
new ValidationErrorHandler( "" ),
value,
DateTimeTools.DayMonthYearFormats.Concat( DateTimeTools.MonthDayYearFormats ).ToArray(),
false,
DateTime.MinValue,
DateTime.MaxValue )
.Error( out var detectedDate ) is null ) {
setOrAddCellStyle( cell, date: true );
cell.Value = detectedDate;
return;
}

v = new Validator();
v.GetEmailAddress( new ValidationErrorHandler( "" ), value, false );
if( !v.ErrorsOccurred ) {
if( new Validator().GetEmailAddress( new ValidationErrorHandler( "" ), value, false ).Error( out _ ) is null ) {
cell.Value = value;
cell.SetHyperlink( new XLHyperlink( "mailto:" + value ) );
return;
}

v = new Validator();
var validatedUrl = v.GetUrl( new ValidationErrorHandler( "" ), value, false );
if( !v.ErrorsOccurred ) {
if( new Validator().GetUrl( new ValidationErrorHandler( "" ), value, false ).Error( out var validatedUrl ) is null ) {
cell.Value = value;
cell.SetHyperlink( new XLHyperlink( validatedUrl ) );
return;
Expand Down
2 changes: 1 addition & 1 deletion Tewl/IO/FileReader.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System.IO;
using System.IO;
using System.Text;
using JetBrains.Annotations;

Expand Down
18 changes: 11 additions & 7 deletions Tewl/IO/IoMethods.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System.Net;
using System.Net;
using System.Text;
using System.Threading;

namespace Tewl.IO;
Expand Down Expand Up @@ -146,13 +147,16 @@ public static long GetFolderSize( string path ) =>
File.Exists( path ) ? new FileInfo( path ).Length : Directory.GetFileSystemEntries( path ).Sum( filePath => GetFolderSize( filePath ) );

/// <summary>
/// Returns a text writer for writing a new file or overwriting an existing file.
/// Automatically creates any folders needed in the given path, if necessary.
/// We recommend passing an absolute path. If a relative path is passed, the working folder
/// is used as the root path.
/// Caller is responsible for properly disposing the stream.
/// Returns a text writer for writing a new file or overwriting an existing file, using UTF-8 encoding. Automatically creates any folders needed in the given
/// path, if necessary. We recommend passing an absolute path. If a relative path is passed, the working folder is used as the root path. Caller is
/// responsible for properly disposing the stream.
/// </summary>
public static TextWriter GetTextWriterForWrite( string filePath ) => new StreamWriter( GetFileStreamForWrite( filePath ) );
/// <param name="filePath"></param>
/// <param name="includeBom">Pass true to include a byte-order mark (BOM) indicating that the file is encoded with UTF-8. This helps avoid misinterpreted
/// characters when reading the file, especially if it is plain text. Pass false for XML files or any other format that has its own encoding declaration.
/// </param>
public static TextWriter GetTextWriterForWrite( string filePath, bool includeBom ) =>
new StreamWriter( GetFileStreamForWrite( filePath ), new UTF8Encoding( includeBom, true ) );

/// <summary>
/// Returns a file stream for writing a new file or overwriting an existing file.
Expand Down
Loading