Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
2d5df29
Update to .NET 10
codeconscious Sep 14, 2026
5247869
Update packages
codeconscious Sep 14, 2026
e198481
Add CCFSharpUtils
codeconscious Sep 14, 2026
ee8ac5d
Add separator tests
codeconscious Sep 14, 2026
8a6ebab
Use String.stripSubstrings from my library
codeconscious Sep 14, 2026
2f843af
Combine Option.map calls
codeconscious Sep 14, 2026
039e5ba
Use the F#+ option keyword
codeconscious Sep 14, 2026
00bcd7a
Use String.hasNoText
codeconscious Sep 15, 2026
7e70cbe
Use option keyword
codeconscious Sep 15, 2026
8d24c2c
Update package
codeconscious Sep 15, 2026
58d4109
Use Num.isEven
codeconscious Sep 15, 2026
4d480ef
Various updates
codeconscious Sep 15, 2026
23b1697
Remove superfluous sleep function
codeconscious Sep 15, 2026
97c6028
Use map and iter; etc.
codeconscious Sep 15, 2026
f8a0b43
Rename OptionType to AppOption
codeconscious Sep 16, 2026
9ce259b
Rename ErrorType to AppError
codeconscious Sep 16, 2026
3bb87b1
Rename getMessage to errorMsg and make minor tweaks
codeconscious Sep 16, 2026
375a7b8
Improve matching
codeconscious Sep 16, 2026
1985de8
Nomenclature
codeconscious Sep 16, 2026
b470de5
Use Array.head and .tail; etc.
codeconscious Sep 16, 2026
7abbce2
Remove unneeded variables
codeconscious Sep 16, 2026
5033dac
Refactor ArgumentValidation
codeconscious Sep 17, 2026
da0588f
Use Result.bimap
codeconscious Sep 17, 2026
376fdd5
Rename function
codeconscious Sep 17, 2026
ed187dc
Rename function to tryParseInRange
codeconscious Sep 17, 2026
31211bb
Replace 3 functions with overloaded methods
codeconscious Sep 17, 2026
916a30f
Move Num type culture to static let
codeconscious Sep 17, 2026
35c0cd0
Code layout
codeconscious Sep 17, 2026
8cab1a8
Rename text to maybeText
codeconscious Sep 17, 2026
72efee5
Remove parens
codeconscious Sep 17, 2026
991394f
Rename errors; tweak error messages
codeconscious Sep 17, 2026
183b10a
Use 'function' for matching
codeconscious Sep 17, 2026
7f4b597
Tweak error message wording
codeconscious Sep 17, 2026
cd48dda
Create stripSeparatorsAndTrim func
codeconscious Sep 17, 2026
a0823dc
Merge remote-tracking branch 'refs/remotes/origin/2026-tweaks' into 2…
codeconscious Sep 17, 2026
f02d1ea
Rename func
codeconscious Sep 17, 2026
2c1d8db
Rename Create to TryCreate
codeconscious Sep 18, 2026
29c6a0e
DU on one line
codeconscious Sep 18, 2026
bf70428
Minor code tweaks
codeconscious Sep 18, 2026
78808e8
Rename binding
codeconscious Sep 18, 2026
ad7fd65
Refactor generateSingle to use a StringBuilder
codeconscious Sep 19, 2026
e3f0932
Update error text
codeconscious Sep 19, 2026
0e91a7c
Rename func to tryParseInRange
codeconscious Sep 19, 2026
3bfe634
Fix string generation test
codeconscious Sep 19, 2026
65dc4a3
Use lists over arrays
codeconscious Sep 19, 2026
0229e20
Use fixed character bank
codeconscious Sep 19, 2026
ab634af
Rename func
codeconscious Sep 19, 2026
bb761ef
Don't trim the prefix
codeconscious Sep 19, 2026
9d78de2
Check for invalid chars
codeconscious Sep 19, 2026
7434f1a
Use actual invalid-paths method
codeconscious Sep 19, 2026
8e8b5f1
Validate extension chars too
codeconscious Sep 19, 2026
9931c15
Shorten option blocks
codeconscious Sep 19, 2026
cb9764b
Update test
codeconscious Sep 19, 2026
26cddf5
Tweak error code
codeconscious Sep 20, 2026
51bb48d
Refactor validateChars
codeconscious Sep 20, 2026
303ebb7
Revert 'String.'
codeconscious Sep 20, 2026
8945b7c
Merge branch 'main' into check-for-invalid-chars
codeconscious Sep 20, 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
20 changes: 15 additions & 5 deletions src/UniqueFileGenerator.Console/Arguments/ArgumentTypes.fs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ namespace UniqueFileGenerator.Console
open Errors
open Utilities
open System
open System.IO
open FSharpPlus
open CCFSharpUtils.Text

Expand All @@ -18,6 +19,15 @@ module ArgTypes =
|> tryParseInRange (floor, ceiling)
|> Result.mapError (fun _ -> NumberParseFailure (text, (floor, ceiling)))

/// Determines whether a string contains characters invalid for filnames on this OS.
let validateChars text =
let invalidChars = Path.GetInvalidFileNameChars() |> Set.ofArray
let isInvalidChar ch = Set.contains ch invalidChars
let rejectedChars = String.filter isInvalidChar text
if String.hasNoText rejectedChars
then Ok text
else Error (rejectedChars |> String.toList |> InvalidChars)

type FileCount = private FileCount of int with
static member val AllowedRange = 1, Int32.MaxValue

Expand All @@ -36,8 +46,8 @@ module ArgTypes =

static member Create maybeText =
maybeText
|> option id Prefix.Default
|> Prefix
|> option validateChars (Ok Prefix.Default)
|> map Prefix

member this.Value = let (Prefix prefix) = this in prefix

Expand All @@ -50,7 +60,7 @@ module ArgTypes =
|> option
(stripSeparatorsAndTrim >> tryParseInRange NameBaseLength.AllowedRange)
(Ok NameBaseLength.Default)
|> Result.map NameBaseLength
|> map NameBaseLength

member this.Value = let (NameBaseLength length) = this in length

Expand All @@ -59,8 +69,8 @@ module ArgTypes =

static member Create maybeText =
maybeText
|> option String.trim Extension.Default
|> Extension
|> option (validateChars >> map String.trim) (Ok Extension.Default)
|> map Extension

member this.Value = let (Extension ext) = this in ext

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,9 +55,9 @@ module ArgValidation =
let! optionMap = toPairs (Array.tail args)

let tryGetArg x = Map.tryFind flags[x] optionMap
let p = Prefix.Create (tryGetArg Prefix)
let! p = Prefix.Create (tryGetArg Prefix)
let! b = NameBaseLength.TryCreate (tryGetArg NameBaseLength)
let e = Extension.Create (tryGetArg Extension)
let! e = Extension.Create (tryGetArg Extension)
let o = OutputDirectory.Create (tryGetArg OutputDirectory)
let! s = Size.TryCreate (tryGetArg Size)
let! d = Delay.TryCreate (tryGetArg Delay)
Expand Down
10 changes: 9 additions & 1 deletion src/UniqueFileGenerator.Console/Errors.fs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
namespace UniqueFileGenerator.Console

open Utilities
open CCFSharpUtils.Text
open FSharpPlus

module Errors =

Expand All @@ -11,6 +13,7 @@ module Errors =
| UnknownFlags
| DuplicateFlags
| NumberParseFailure of Input: string * AllowedRange: (int * int)
| InvalidChars of Chars: char list
| DirectoryMissing of string
| DriveSpaceConfirmationFailure
| DriveSpaceInsufficient of Needed: string * Actual: string
Expand All @@ -24,7 +27,12 @@ module Errors =
| UnknownFlags -> "Unknown option flag(s) found."
| DuplicateFlags -> "Duplicate option flag(s) found. Each can only be used once."
| NumberParseFailure (input, (floor, ceiling)) ->
$"The number \"%s{input}\" is out of bounds. Enter an integer between %s{Num.Format floor} and %s{Num.Format ceiling}, inclusive."
sprintf "\"%s\" is an invalid value. Enter an integer between %s and %s, inclusive."
input (Num.Format floor) (Num.Format ceiling)
| InvalidChars chars ->
sprintf "Found %s invalid for file names on this system: \"%s\"."
(String.pluralizeSWithCount "character" chars.Length) // "1 character," "2 characters," etc.
(chars |> map string |> String.concat "\", \"")
| DirectoryMissing dirName -> $"Directory \"%s{dirName}\" was not found."
| DriveSpaceConfirmationFailure -> "Could not confirm available drive space."
| DriveSpaceInsufficient (needed, actual) ->
Expand Down
11 changes: 8 additions & 3 deletions src/UniqueFileGenerator.Tests/ArgParserTests.fs
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,19 @@ let validOptionValues =
Delay, "5_000" ]

let defaultOptions =
{ Prefix = Prefix.Create None |> _.Value
{ Prefix = Prefix.Create None
|> function
| Ok x -> x.Value
| Error e -> failwith $"Unexpected parse error: {e}"
NameBaseLength =
NameBaseLength.TryCreate None
|> function
| Ok x -> x.Value
| Error e -> failwith $"Unexpected parse error: {e}"
Extension = Extension.Create None |> _.Value
Extension = Extension.Create None
|> function
| Ok x -> x.Value
| Error e -> failwith $"Unexpected parse error: {e}"
OutputDirectory = OutputDirectory.Create None |> _.Value
Size = Size.TryCreate None
|> function
Expand Down Expand Up @@ -379,4 +385,3 @@ module SupportedSeparators =
let result = stripSeparatorsAndTrim text

Assert.Equal("helloworld\ttestexample\nmore", result)

Loading