fix: support Hunspell flag aliases and lazy affix expansion - #1160
Open
fmagnucz wants to merge 1 commit into
Open
fix: support Hunspell flag aliases and lazy affix expansion#1160fmagnucz wants to merge 1 commit into
fmagnucz wants to merge 1 commit into
Conversation
fmagnucz
force-pushed
the
fix/hunspell-flag-aliases
branch
from
August 30, 2026 15:37
63b2143 to
4c0077c
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
Vale previously expanded every Hunspell dictionary entry eagerly while loading
the dictionary. It generated all reachable prefixed, suffixed, cross-product,
and continuation forms, then retained every generated surface form in memory.
This approach becomes impractical for highly inflected languages. With the
Hungarian
hu_HUdictionary:1.7 GiB of memory.
Correctly parsing Hunspell flag aliases made this problem more visible because
the aliases enabled many affix rules that Vale had previously ignored.
The affected dictionaries also exposed several compatibility issues:
AFalias indices from.dicentries were interpreted as literal flags;AFalias indices in affix-rule continuation fields were also interpreted asliteral flags, so later suffixes in a chain were never reached;
.affand.dicfiles;expressions interpreted it as a range;
entry flags, causing valid Italian words such as
dito be rejected;so Unicode words could be skipped before dictionary lookup.
Solution
AFflag alias tables and resolve aliases in both.dicentries and affix continuation fields;
.affand.dicfiles;
derived surface form;
exact forward validation;
reverse-reachable candidates, avoiding the combinatorial expansion exposed by
real Hungarian continuation aliases;
homographs, and suggestions;
and uppercase checks while retaining the ASCII fast path;
cross-products, compounds, suggestions, and the Italian
dicase.Follow-up regressions
A Hungarian AsciiDoc reproducer exposed that affix continuation values also use
the
AFalias table. Native Hunspell accepts the inflected formsszoftvertervezőt,képeslapot,lekérdezéseket,kigondolása,készítése,and
dokumentálása. Vale now accepts the same forms, while the intentional typoszoftvvvvertervezőtis still reported.A minimal
AF 2fixture verifies that a rule such asSFX A 0 ed/2 .resolvescontinuation alias
2instead of treating it as a literal flag.The default spelling filters now pass Unicode words to the dictionary checker
and still skip words ending in Unicode uppercase letters. The spelling
end-to-end expectation was updated to confirm that the Japanese token
オプションis no longer silently skipped.Performance
Measurements used the system Hungarian
hu_HUdictionary.The eager full-dictionary figure is not presented as a completed benchmark:
the approximately 370-million-form value is an extrapolation from the
controlled 1,000-entry sample.
On the supplied Hungarian AsciiDoc reproducer, the pruned continuation lookup
completed in approximately 0.46–0.60 s. The earlier lookup took about 7.17 s,
while resolving continuation aliases without reverse-reachable pruning did not
complete within 90 s.
Automated testing
The following checks passed on the final implementation:
go test ./internal/spellgo test -race ./internal/spellgo vet ./internal/spellgo test ./internal/checkgo test ./internal/e2e -run 'TestScenarios/checks/spelling'gofmton all changed Go filesgit diff --check v3...HEADA full
go test ./...run was attempted for the follow-up. It could notcomplete in the restricted environment because package synchronization
required unavailable network access and a Snap test required
cap_dac_override. The generated Tree-sitter Lua NUL-character compilerwarning was non-fatal.
golangci-lintwas not available locally.Cross-language smoke tests
Five dictionaries with different flag formats and morphological characteristics
were tested:
en_USde_DEfromhunspell-de-de20161207-12it_ITfromhunspell-it1:24.2.1-1frfromhunspell-fr-classical1:7.0-1ru_RUfromhunspell-ru1:24.2.1-1Each sentence was checked first with native Hunspell and then with the final
Vale CLI after the follow-up fixes. In every language, the correct sentence
produced no alerts and the misspelled sentence produced exactly the same three
alerts in native Hunspell and Vale.
English —
en_USCorrect:
Misspelled:
Detected:
carefull,revievs,documentaton.German —
de_DECorrect:
Misspelled:
Detected:
Entwikler,Dokumentazion,zuverlassige.Italian —
it_ITCorrect:
Misspelled:
Detected:
svilupatrice,documentazzione,aggiornatto.The correct sentence deliberately includes
di, covering the Italiansingle-byte flag regression.
French —
frCorrect:
Misspelled:
Detected:
dévelopeuse,documentattion,programne.Russian —
ru_RUCorrect:
Misspelled:
Detected:
разработтчик,внимателно,докуминтацию.