feat: add SstData with DictionaryFile and word knowledge

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-01 15:06:55 +02:00
co-authored by Claude Sonnet 5.5
parent af1acdc0fa
commit a5fa0686f0
6 changed files with 273 additions and 0 deletions
@@ -0,0 +1,52 @@
import Testing
@testable import SstData
struct DictionaryFileTests {
let sample = "# Opmerking\nAnthropic\n\ncloud code => Claude Code\n"
@Test func parsesTermsPairsCommentsAndBlanks() {
let file = DictionaryFile(parsing: sample)
#expect(file.lines.count == 4)
#expect(file.entries == [term("Anthropic"), pair("cloud code", "Claude Code")])
#expect(file.lines[0] == .comment("# Opmerking"))
#expect(file.lines[2] == .blank)
}
@Test func roundTripKeepsCommentsBlankLinesAndOrder() {
#expect(DictionaryFile(parsing: sample).serialized() == sample)
}
@Test func normalisesSpacingAroundTheArrow() {
#expect(DictionaryFile(parsing: "a=>b\n").serialized() == "a => b\n")
#expect(DictionaryFile(parsing: " cloud code => Claude Code \n").entries == [pair("cloud code", "Claude Code")])
}
@Test func unreadableLinesAreKeptAsInvalid() {
let file = DictionaryFile(parsing: "oops =>\n=> nothing\nok\n")
#expect(file.lines[0] == .invalid("oops =>"))
#expect(file.lines[1] == .invalid("=> nothing"))
#expect(file.serialized() == "oops =>\n=> nothing\nok\n")
}
@Test func handlesWindowsLineEndingsAndMissingFinalNewline() {
let file = DictionaryFile(parsing: "a\r\nb => c")
#expect(file.entries == [term("a"), pair("b", "c")])
#expect(file.serialized() == "a\nb => c\n")
}
@Test func emptyTextIsAValidEmptyFile() {
#expect(DictionaryFile(parsing: "").entries.isEmpty)
#expect(DictionaryFile(parsing: "").serialized() == "")
}
@Test func appendUpdateAndRemove() {
var file = DictionaryFile(parsing: "# c\n")
let id = file.append(.term("Vercel"))
#expect(file.entries == [term("Vercel")])
file.update(id: id, kind: .correction(heard: "versel", wrote: "Vercel"))
#expect(file.entries == [pair("versel", "Vercel")])
file.remove(id: id)
#expect(file.entries.isEmpty)
#expect(file.serialized() == "# c\n")
}
}
+13
View File
@@ -0,0 +1,13 @@
import Foundation
@testable import SstData
/// Deterministic stand-in for the macOS spell checker.
struct FakeKnowledge: WordKnowledge {
var words: Set<String> = ["cloud", "code", "some", "thing", "something", "reef", "slack", "in", "de", "the", "of"]
var functionWords: Set<String> = ["in", "de", "the", "of"]
func isWord(_ word: String) -> Bool { words.contains(word.lowercased()) }
func isFunctionWord(_ word: String) -> Bool { functionWords.contains(word.lowercased()) }
}
func term(_ text: String) -> DictionaryEntry { DictionaryEntry(kind: .term(text)) }
func pair(_ heard: String, _ wrote: String) -> DictionaryEntry { DictionaryEntry(kind: .correction(heard: heard, wrote: wrote)) }
@@ -0,0 +1,24 @@
import Testing
@testable import SstData
struct SystemWordKnowledgeTests {
let knowledge = SystemWordKnowledge()
@Test func recognisesEnglishAndDutchWords() {
#expect(knowledge.isWord("cloud"))
#expect(knowledge.isWord("Cloud"))
#expect(knowledge.isWord("vandaag"))
}
@Test func doesNotTreatProductNamesAsWords() {
#expect(!knowledge.isWord("vercel"))
#expect(!knowledge.isWord("supabase"))
#expect(!knowledge.isWord("anthropic"))
}
@Test func functionWordsComeFromTheBuiltInList() {
#expect(knowledge.isFunctionWord("de"))
#expect(knowledge.isFunctionWord("The"))
#expect(!knowledge.isFunctionWord("vercel"))
}
}