@sinhala-typer/typing-engine
v0.1.0
Published
Framework-agnostic, zero-dependency Sinhala transliteration engine (phonetic + Wijesekara input methods, plus a legacy-font converter), with zero DOM/browser dependencies and a pluggable LanguageModule interface for future languages.
Maintainers
Readme
@sinhala-typer/typing-engine
A framework-agnostic, zero-dependency Sinhala transliteration engine —
phonetic (ammaa → අම්මා) and Wijesekara keyboard input methods, plus a
legacy 8-bit font converter, with zero DOM/browser API dependencies. It's
a pure (state, keystroke) → { state, edit } function: you own the text
buffer, this library only tells you what to change.
Designed to be reusable from React, Vue, Angular, Node.js, Electron, VS Code
extensions, or browser extensions — see
@sinhala-typer/typing-engine-dom for a ready-made
browser <textarea> adapter if you're building a web UI.
Install
npm install @sinhala-typer/typing-engineUsage
import { getLanguage, type EngineState } from "@sinhala-typer/typing-engine";
const sinhala = getLanguage("si")!;
const phonetic = sinhala.inputMethods.find((m) => m.id === "phonetic")!;
let state: EngineState = phonetic.initialState();
let text = "";
function press(char: string) {
const { state: nextState, edit } = phonetic.type(state, { char });
state = nextState;
text = text.slice(0, text.length - edit.deleteCount) + edit.insertText;
}
for (const ch of ["a", "m", "m", "a", "a"]) press(ch);
console.log(text); // "අම්මා"Backspace is a separate method, since it's not just "undo the last edit" — it always removes exactly one character, even mid-conjunct:
const { state: nextState, edit } = phonetic.backspace(state);
state = nextState;
text = text.slice(0, text.length - edit.deleteCount) + edit.insertText;After any change your engine didn't produce (paste, undo, programmatic edit, cursor move), resync state from the actual buffer:
state = phonetic.resync(text, caretIndex);API
getLanguage(id)/listLanguages()/registerLanguage(module)— the language registry. Sinhala ("si") is registered automatically on import.- A
LanguageModuleexposesinputMethods: InputMethod[]and an optionalconvertLegacyFont(text). - An
InputMethod(e.g.phonetic,wijesekara) exposes:initialState()— a fresh, empty composition state.type(state, keystroke)→{ state, edit }.backspace(state)→{ state, edit }— always deletes exactly one character.resync(text, caretIndex)→ rebuilds state from arbitrary buffer content.
Edit = { deleteCount: number; insertText: string }— deletedeleteCountcharacters immediately before the caret, then insertinsertText. Applying it is your responsibility; this library never touches a text buffer itself.UndoStack— a small generic undo/redo helper (you supply the applied edit and its inverse; it just sequences them).
Supported languages
Sinhala only, for now. The LanguageModule interface is designed to support
additional languages later, but hasn't been validated against a second
language yet — see the root docs/OPEN_QUESTIONS.md.
Correctness
Every composition rule (vowel doubling, rakaransaya/yansaya ZWJ conjuncts,
diphthongs, sanyaka nasalization, and more — see
docs/GLOSSARY.md) is covered by a keystroke-trace
unit test in tests/. The engine was originally ported from a legacy
implementation and verified against it via differential fuzz testing
(thousands of randomized keystroke sequences, comparing output and internal
state after every keystroke) before being considered correct.
License
MIT
