feat(ucase): add default case mapping package#15
Conversation
Implement the Unicode default (language-insensitive) case algorithms from The Unicode Standard, Section 3.13 'Default Case Algorithms': full case folding, lower/upper/titlecasing, the Cased and Case_Ignorable properties, and default caseless matching. Tables are generated from Unicode 17.0.0 UCD data. Tests verify every default mapping and both properties against the committed UCD files and, when online, against the official files downloaded from unicode.org.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 50f6b32994
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| // Case-ignorable characters do not change word state. | ||
| out = appendMapping(out, runes, i, kindLower) | ||
| default: | ||
| inWord = false |
There was a problem hiding this comment.
Preserve UAX #29 word spans in ToTitle
When ToTitle sees any character that is neither Cased nor Case_Ignorable, this branch ends the current word. That splits Unicode word spans at digits and connector punctuation even though the default titlecase algorithm is defined over UAX #29 word boundaries; the repository's UAX #29 implementation keeps Numeric × AHLetter and _ (ExtendNumLet) inside the same word (uax29/word.go:165-197, uax29/word_data.go:22-26). As a result ToTitle("version2BETA") currently returns Version2Beta instead of Version2beta, and FOO_BAR becomes Foo_Bar, so common identifiers/version strings are visibly over-titlecased.
Useful? React with 👍 / 👎.
Summary
Adds
ucase, implementing the Unicode default (language-insensitive) case algorithms from The Unicode Standard, Section 3.13 "Default Case Algorithms".Case mapping is specified in the core standard (not a numbered UAX/UTS annex), so the package is named for its function —
ucase— rather than following theuaxNN/utsNNpattern. The rationale is documented in the package README.Public API
ToFold,ToLower(incl.Final_Sigma),ToUpper,ToTitleSimpleFold,SimpleLower,SimpleUpper,SimpleTitleIsCased(D135),IsCaseIgnorable(D136),CaselessMatch(D144)UnicodeVersion("17.0.0")Data & generation
Tables are generated by
generate_ucase.gofrom Unicode 17.0.0 UCD data (UnicodeData.txt,SpecialCasing.txt,CaseFolding.txt,DerivedCoreProperties.txt), which are committed as test vectors per repo idiom. The generator is version-pinned, deterministic (code-point-sorted),go/format-formatted, and has zero external dependencies.Tests
TestDataFileConsistency— verifies every default mapping and both properties against the committed UCD files (full code-space sweep forCased/Case_Ignorable).TestOfficialConformance— re-verifies against files downloaded live from unicode.org (skipped offline / in-short).ß→SS, ligatures, final sigma, titlecasing),CaselessMatch, idempotency, and runnable examples.Scope / non-goals
tr/az, Lithuanianlt) are intentionally out of scope; the only context condition exercised by the default algorithm isFinal_Sigma. Documented as future work.CaselessMatchimplements the default caseless match (D144), not the canonical (D145) match (no NFD normalization).gofmt -l,go vet, andgo test ./...all pass.