You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
HasMinimumLines/HasMaximumLines/HasExactLines don't count a lone \r or Unicode line separator, contradicting IsMultiLine/IsSingleLine: "a\rb" is multi-line but has "1 line" #299
The five line-related validation attributes in Semantics.Strings/Validation/Attributes/Format/ disagree on what a line break is.
IsSingleLineAttribute and IsMultiLineAttribute treat '\n', '\r' and any UnicodeCategory.LineSeparator character as a line break.
HasMinimumLinesAttribute, HasMaximumLinesAttribute and HasExactLinesAttribute count lines as value.Count(c => c == '\n') + 1.
The \r\n "don't double count" block in those three changes nothing. It computes crlfCount + (lfTotal - crlfCount) + 1, which equals the original lfTotal + 1.
Failure scenario
For "a\rb", and for "a b":
Attribute
Result
[IsMultiLine]
valid
[IsSingleLine]
invalid
[HasMinimumLines(2)]
invalid (counts 1 line)
[HasMaximumLines(1)]
valid
[HasExactLines(2)]
invalid
Why it matters
These attributes are meant to be combined. [HasMaximumLines(1)] lets through strings that [IsSingleLine] rejects.
[IsMultiLine, HasMinimumLines(2)] rejects a string that IsMultiLine just accepted.
Classic Mac line endings, and text containing U+2028, bypass line-count limits entirely.
Suggested fix
Add one shared helper, for example internal static int CountLines(string value), and use it in all three Has*Lines attributes. It should treat \r\n as one break, and a lone \r, \n, U+2028 or U+2029 as one break each. Remove the no-op CRLF block.
Acceptance criteria
"a\rb", "a\nb", "a\r\nb" and "a b" each count as 2 lines in HasMinimumLines, HasMaximumLines and HasExactLines.
Priority: Medium. It is a validation inconsistency: combined attributes contradict each other, and a lone \r or U+2028 slips past line-count limits. The failure is a wrong accept or reject, not a crash.
Area / suggested assignment:Semantics.Strings/Validation/Attributes/Format/ (HasMinimumLines, HasMaximumLines, HasExactLines)
Duplicates: none found among open issues in the org
In progress: no matching open PR
Notes: A shared CountLines helper, matching the break definition IsMultiLine/IsSingleLine already use, fixes all three attributes at once. Deleting the no-op CRLF block is a free cleanup.
Activity
matt-edmondson commentedon Sep 28, 2026
Triage
\ror U+2028 slips past line-count limits. The failure is a wrong accept or reject, not a crash.Semantics.Strings/Validation/Attributes/Format/(HasMinimumLines,HasMaximumLines,HasExactLines)Notes: A shared
CountLineshelper, matching the break definitionIsMultiLine/IsSingleLinealready use, fixes all three attributes at once. Deleting the no-op CRLF block is a free cleanup.Generated by Claude Code
[patch] Count every line break in HasMinimumLines, HasMaximumLines an…