- This repository hosts McTabimWeb (小麥他命輸入法), a TypeScript engine for table-based Chinese input methods like Changjie (倉頡), Sucheng (速成), Dayi (大易), and Array (行列).
- It is designed to be embedded in web pages and also runs on Chrome OS and Windows (via the PIME framework).
- Distribution bundles live in
dist/, while TypeScript sources are undersrc/. - The public entry points are exported from
src/index.ts. Treat this package like a reusable library—avoid leaking experimental APIs.
- Data layer (
src/data/):InputTableManagerlazily loads CIN tables plus emoji/symbol metadata. It is a singleton accessed throughInputTableManager.getInstance(). Preserve that pattern and prefer readonly properties when exposing tables. - Input table wrappers:
InputTableWrapperinsrc/data/InputTableWrapper.tsis now an interface. UseGeneralInputTableWrapperfor regular tables,BopomofoInputTableWrapperfor standard Bopomofo tables, andWslInputTableWrapperfor 吳守禮 tables. Prefer polymorphism over adding table-type conditionals or enum flags. - BPMF homophone lookup: Bopomofo readings come from
src/data/cin/bpmf.jsonviaInputTableManager.lookupBpmfReadingsandlookupCandidatesForBpmfRadicals. Keep the table lazy-loaded throughBopomofoInputTableWrapper. - Input pipeline (
src/input_method/):InputControllerorchestrates state transitions (EmptyState,InputtingState,CommittingState) and keeps UI + KeyHandler in sync. Any change to state creation usually needs companion updates inInputUIStateBuilderand the associated Jest specs in the same folder. - Key handling:
Key,KeyHandler, andKeyMappingwork together; favor pure functions that accept the currentSettingsandInputTableWrapperso behavior stays testable. Never reference DOM APIs from these modules. - Phonetic handling:
KeyHandlershould depend on wrapper polymorphism (isPhoneticTable,createSyllable) instead of checking a table type field. If a new phonetic table is introduced, add a new wrapper implementation rather than branching inKeyHandler. - Homophone selection states:
SelectingHomophoneReadingsStateandSelectingHomophoneWordStateare entered fromKeyHandlerwhen the backtick key triggers a BPMF homophone lookup. ESC/backspace should exit back to the prior state. - Platform-specific shims: ChromeOS and PIME entrypoints (
src/chromeos_ime.ts,src/pime.ts,src/pime_keys.ts) should stay thin and call into the sharedInputController.- The ChromeOS extension (
src/chromeos_ime.ts) also implements a context menu feature. When text is selected or an editable area is focused, a 'lookup' option appears. Activating this option performs a reverse radical lookup using theInputTableManagerand sends the result to the content script. - Help pages for Chrome OS and PIME are provided in
output/chromeos/help/index.htmlandoutput/pime/help.htmlrespectively. - The Web example uses SimpleKeyboard for a virtual on-screen keyboard (
output/example/index.js).
- The ChromeOS extension (
- Use modern TypeScript (target TS 5.9). Prefer
const+ arrow functions, explicit return types on exported symbols, and named exports (no default exports in this repo). - Keep data-structure types close to their usage (e.g., interfaces in the same file). Add brief inline comments only for non-obvious logic such as Unicode range calculations in
InputTableManager. - When mutating state, create new objects instead of altering inputs in place—most consumers rely on immutability for predictable UI rendering.
- Always follow Kent Beck's TDD flow: write a failing test, make it pass, then refactor.
- Unit tests are required for all new or modified code. Place tests beside implementation files as
*.test.ts. - When code is modified, also update this copilot-instructions.md file if relevant.
- Jest with
ts-jestis configured; high-signal tests already exist beside the implementation files (*.test.ts). - Webpack for JSON: The project uses webpack to bundle CIN tables. To optimize the size, a custom
json-minifier-loader.jsis used to minify JSON files. The webpack configuration explicitly targets JSON files with a?rawresource query, likeimport '../data/cin/array30.json?raw'. - Use
npm run ts-buildfor type-checking andnpm run eslintto enforce the TypeScript ESLint ruleset. Keep CI-friendly scripts free of watch flags. - AI agents may call
test:coverage(via agent) to find code not covered by tests and should address coverage gaps.
- The canonical Copilot guidance lives in
.github/copilot-instructions.md. GEMINI.mdandAGENT.mdare link-only entrypoints. Update the canonical file instead of treating those files as independent documentation.- Update this file when introducing new subsystems so Copilot understands how to wire things together.
- Prefer concise prose and actionable bullet points that tell Copilot what to favor or avoid rather than lengthy narratives.
- Follow Conventional Commits for every commit title (e.g.,
feat: add reverse lookup cache). - Always include 3–4 short lines after the title that summarize the change, rationale, and any testing performed so history stays self-explanatory.