feat(languagetool): real grammar-check service (checkText + offset-safe apply)#235
Conversation
…fe apply) The foundation for the editor grammar feature, beyond the connectivity ping in languageToolClient.ts. checkText() POSTs /v2/check, parses matches[] into a normalized shape (offset/length/message/replacements/rule/category), slices the flagged span from the source for reliable display + dictionary matching, caches by text hash (dictionary applied post-cache so a new word never re-fetches), is abortable, and degrades silently to an empty result on any network/HTTP failure. applyMatchReplacement() applies one suggestion offset-safe with an anchor check so stale offsets can never corrupt the text. Privacy-first: never logs manuscript text. Locale gating uses getLanguageToolCode() from the SSOT (PR #234). 13 tests cover parsing, empty-text short-circuit, caching, dictionary filtering (spelling-only), replacement cap, out-of-range drop, offline/error degradation, abort rethrow, and offset-safe apply. Gating is covered by languageToolClient.test. Stacked: the 'Check this scene' panel + hook + i18n land in the next PR. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
|
Overall Grade |
Security Reliability Complexity Hygiene |
Code Review Summary
| Analyzer | Status | Updated (UTC) | Details |
|---|---|---|---|
| Docker | Jun 24, 2026 8:40p.m. | Review ↗ | |
| JavaScript | Jun 24, 2026 8:40p.m. | Review ↗ | |
| CSS | Jun 24, 2026 8:40p.m. | Review ↗ | |
| Rust | Jun 24, 2026 8:40p.m. | Review ↗ |
Important
AI Review is run only on demand for your team. We're only showing results of static analysis review right now. To trigger AI Review, comment @deepsourcebot review on this thread.
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
Touching a new file surfaces its short-identifier names as introduced anti-patterns. Rename c→code, r→rep, s→val, w→word, m→raw/match to clear JS-C1002 (keep the conventional loop index i). No behavior change. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
DeepSource analyzes tests/unit/ too; JS-C1002 flags const/let declarations. Rename const m → firstMatch. No behavior change. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…e loop (#237) * docs(deepsource): inline review threads now resolvable — reply+resolve loop (§1/§3a/§11) DeepSource began posting inline PR review comments in resolvable threads (deepsource-io[bot]) on code PRs #235/#236 — the earlier 'no resolveReviewThread step' note is obsolete. Update the loop to: fix → status green → reply citing the commit + resolveReviewThread, 0 unresolved (mirrors CodeAnt). Add §3a GraphQL snippet, correct the status-vs-check-run reality (read commits/$SHA/status + target_url), and log the JS-C1002/JS-0357 + tests/unit-is-analyzed + codecov/patch lessons. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * docs(deepsource): termination condition also requires 0 unresolved threads Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
* docs(languagetool): feature guide + ADR 0010 + CHANGELOG + README Document the shipped LanguageTool integration (registry metadata #234, service #235, on-demand panel #236, live inline overlay #238): docs/LANGUAGETOOL.md (setup, privacy model, locale coverage, architecture), ADR 0010 (self-hosted + overlay-reuse + locale-mapping rationale), CHANGELOG [Unreleased] entry, README feature line + Documentation Hub row. Locale-addition rollout (pl/nl/tr/uk/ro) is tracked separately and intentionally not covered here. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * docs(i18n): dedicated TODO for the LanguageTool new-locale rollout (deferred) Self-contained plan for the remaining program tail — adding pl/nl/tr/uk/ro UI locales (per-locale recipe, LT metadata, sequencing, gotchas) + the locale-dependent closing docs (README 19→24, handover report). Deferred for later execution after other planned work. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Summary
Second PR of the i18n + real LanguageTool program. Builds the actual grammar-checking core that the scaffold (
languageToolClient.ts— a gate + connectivity ping) only hinted at. No user-facing UI yet; this is the tested foundation the "Check this scene" panel (next PR) consumes.services/languageToolService.tscheckText(text, language, opts)—POST /v2/check, parsesmatches[]into a normalizedLanguageToolMatch(offset/length/message/replacements/ruleId/category/matchedText/isSpelling). The flagged span is sliced from the source text so display + dictionary matching are reliable regardless of server context quirks.AbortSignal.any); a caller abort rethrows (cancellation), our timeout/network failures degrade silently to{ matches: [], status: 'offline' | 'error' }— typing is never blocked.advancedEditor.customDictionary(reused — no new settings field).getLanguageToolCode()from the SSOT (feat(i18n): LanguageTool registry metadata + Phase-0 report (Workstream B) #234), so unsupported locales (tr/he/fi/hu/is/eu/ko) never call this.applyMatchReplacement(text, match, replacement)— offset-safe single-edit apply with an anchor check (only applies if the span still holds the originally-flagged text), so stale offsets after an edit can't corrupt unrelated text.Tests (
tests/unit/languageToolService.test.ts, 13)parsing, empty-text short-circuit, caching, dictionary filtering (spelling-only), non-spelling-not-filtered, replacement cap, out-of-range drop, offline + HTTP-error degradation, abort rethrow, offset-safe apply (+ stale-anchor + out-of-bounds). Gating (
assertLanguageToolAllowed) is covered by the existinglanguageToolClient.test.ts.Test plan
pnpm run lint✅ ·pnpm run typecheck✅pnpm exec vitest run tests/unit/languageToolService.test.ts✅ (13)Next in the stack
PR-C1 UI:
useLanguageToolCheckhook + "Check this scene" panel (apply / ignore / add-to-dictionary) wired into the Writer view + i18n (core-5 hand-translated, Beta via bulk-translate).🤖 Generated with Claude Code