Files
hohoff/src/main/grammarService.ts
2026-06-20 22:18:12 +10:00

75 lines
2.2 KiB
TypeScript

import https from 'https'
import querystring from 'querystring'
export interface GrammarMatch {
offset: number
length: number
message: string
shortMessage: string
replacement: string | null
ruleId: string
categoryId: string
}
const IGNORED_RULE_IDS = new Set([
'WHITESPACE_RULE',
'UNPAIRED_BRACKETS',
'EN_QUOTES',
'DASH_RULE',
'WORD_CONTAINS_UNDERSCORE',
])
export async function checkGrammar(text: string, language = 'en-US'): Promise<GrammarMatch[]> {
return new Promise((resolve, reject) => {
const body = querystring.stringify({ text, language, enabledOnly: 'false' })
const req = https.request(
{
hostname: 'api.languagetool.org',
path: '/v2/check',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': Buffer.byteLength(body),
'Accept': 'application/json',
},
},
(res) => {
let data = ''
res.on('data', (chunk) => { data += chunk })
res.on('end', () => {
try {
const parsed = JSON.parse(data) as {
matches: Array<{
offset: number
length: number
message: string
shortMessage: string
replacements: Array<{ value: string }>
rule: { id: string; category: { id: string } }
}>
}
const matches: GrammarMatch[] = parsed.matches
.filter((m) => !IGNORED_RULE_IDS.has(m.rule.id))
.map((m) => ({
offset: m.offset,
length: m.length,
message: m.message,
shortMessage: m.shortMessage || m.message,
replacement: m.replacements[0]?.value ?? null,
ruleId: m.rule.id,
categoryId: m.rule.category.id,
}))
resolve(matches)
} catch (e) {
reject(new Error(`LanguageTool parse error: ${String(e)}`))
}
})
}
)
req.on('error', reject)
req.setTimeout(15000, () => { req.destroy(); reject(new Error('Grammar check timed out')) })
req.write(body)
req.end()
})
}