Restructure chat service, web routes, and add test suite

Split monolithic chat service into modular structure with Matrix client
support, extract web server into per-resource route modules, introduce
bootstrap/main-loop separation, and add comprehensive vitest coverage
across services, repositories, and utilities. Adds project docs and
CLAUDE.md agent instructions.
This commit is contained in:
jjbrunton committed 2026-05-21 01:32:10 +01:00
1 parent dfa0580859
commit 633bb0ec04
84 files changed
+19278 -3888

No files matched your search

+59
View File
@@ -0,0 +1,59 @@
import { describe, it, expect } from 'vitest';
import { parseGenderTag } from '../src/utils/gender-tag.js';
describe('parseGenderTag', () => {
it('parses bracketed age-then-letter', () => {
expect(parseGenderTag('Bored at home [25F]')).toBe('female');
expect(parseGenderTag('looking for chat [30 M]')).toBe('male');
});
it('parses bracketed letter-then-age', () => {
expect(parseGenderTag('[F25] dtf')).toBe('female');
expect(parseGenderTag('[M, 22] up late')).toBe('male');
});
it('parses parenthesised tags', () => {
expect(parseGenderTag('Hey (25f) here')).toBe('female');
expect(parseGenderTag('(m 30) want to chat')).toBe('male');
});
it('parses X4Y tags', () => {
expect(parseGenderTag('f4m anyone awake?')).toBe('female');
expect(parseGenderTag('M4F looking')).toBe('male');
expect(parseGenderTag('f4mf bored')).toBe('female');
});
it('parses slash-separated age/gender', () => {
expect(parseGenderTag('25/f horny')).toBe('female');
expect(parseGenderTag('m/22 want a chat')).toBe('male');
});
it('parses bare age+letter', () => {
expect(parseGenderTag('hey 25f here')).toBe('female');
expect(parseGenderTag('f25 from UK')).toBe('female');
expect(parseGenderTag('30m looking')).toBe('male');
});
it('is case-insensitive', () => {
expect(parseGenderTag('[25F]')).toBe('female');
expect(parseGenderTag('[25f]')).toBe('female');
});
it('returns null for untagged posts', () => {
expect(parseGenderTag('hey looking for someone fun')).toBeNull();
expect(parseGenderTag('')).toBeNull();
expect(parseGenderTag('any chats?')).toBeNull();
});
it('does not match embedded letters in unrelated words', () => {
// "25 from" should not parse as 25f
expect(parseGenderTag('25 from the UK')).toBeNull();
// "30 minutes" should not parse as 30m
expect(parseGenderTag('30 minutes ago')).toBeNull();
});
it('prefers the first match (the poster, not the target in X4Y)', () => {
expect(parseGenderTag('M4F please dm')).toBe('male');
expect(parseGenderTag('F4M anyone?')).toBe('female');
});
});