diff --git a/client/src/components/MnemonicBuilder.tsx b/client/src/components/MnemonicBuilder.tsx index b0029e4..ddfb5fd 100644 --- a/client/src/components/MnemonicBuilder.tsx +++ b/client/src/components/MnemonicBuilder.tsx @@ -94,7 +94,8 @@ export function MnemonicBuilder({ token, onComplete }: Props) {
{pattern.length} word{pattern.length !== 1 ? 's' : ''} — - {' '}≤3 letters for dots · (short), 4+ letters for dashes — (long). + {' '}≤3 letters for dots ·, 4+ letters for dashes —. + {' '}Start a word with "{letter}" to anchor it!
{ expect(phrase.length).toBeLessThanOrEqual(3) }) }) + it('first word starts with the target letter', () => { + for (const letter of ['A','E','T','S','N','H','R','D','L','I','U','O']) { + const s = suggestPhrases(letter, 5) + s.forEach(phrase => { + expect(phrase[0].toUpperCase()).toBe(letter) + }) + } + }) it('returns empty array for unknown letter', () => { expect(suggestPhrases('$', 5)).toEqual([]) }) @@ -108,40 +116,52 @@ describe('suggestPhrases', () => { describe('validatePhrase', () => { it('accepts valid phrase for E (.)', () => { - expect(validatePhrase('go', 'E')).toEqual({ valid: true }) + expect(validatePhrase('eat', 'E')).toEqual({ valid: true }) }) it('accepts 3-letter dot word', () => { - expect(validatePhrase('run', 'E')).toEqual({ valid: true }) + expect(validatePhrase('eat', 'E')).toEqual({ valid: true }) }) it('accepts valid phrase for A (.-)', () => { - expect(validatePhrase('go WALKING', 'A')).toEqual({ valid: true }) + // A = .- → dot + dash; "age" starts with A, "WALKING" is 4+ + expect(validatePhrase('age WALKING', 'A')).toEqual({ valid: true }) }) it('accepts valid phrase for S (...)', () => { - expect(validatePhrase('go go go', 'S')).toEqual({ valid: true }) + // S = ... → three dot words; "sun" starts with S + expect(validatePhrase('sun go go', 'S')).toEqual({ valid: true }) }) it('rejects 4-letter word in dot position', () => { - const r = validatePhrase('walk go go', 'S') + const r = validatePhrase('walk sun go', 'S') expect(r.valid).toBe(false) }) it('accepts 3-letter word in dot position', () => { - expect(validatePhrase('run', 'E')).toEqual({ valid: true }) + expect(validatePhrase('eat', 'E')).toEqual({ valid: true }) }) it('rejects 3-letter word in dash position', () => { - const r = validatePhrase('go go', 'A') // A=.- so second word must be 4+ letters + const r = validatePhrase('age go', 'A') // A=.- so second word must be 4+ letters expect(r.valid).toBe(false) }) it('accepts 4-letter word in dash position', () => { - expect(validatePhrase('go walk', 'A')).toEqual({ valid: true }) + expect(validatePhrase('aim also', 'A')).toEqual({ valid: true }) }) it('rejects wrong word count', () => { - const r = validatePhrase('go go', 'S') + const r = validatePhrase('sun go', 'S') expect(r.valid).toBe(false) expect(r.message).toContain('3') }) it('rejects long word for dot position', () => { - const r = validatePhrase('WALKING go go', 'S') + const r = validatePhrase('SAILING go go', 'S') expect(r.valid).toBe(false) }) + it('rejects phrase without anchor letter', () => { + // A = .- but no word starts with A + const r = validatePhrase('go walk', 'A') + expect(r.valid).toBe(false) + expect(r.message).toContain('"A"') + }) + it('accepts anchor letter in any position', () => { + // A = .- → "go ALSO" — "ALSO" starts with A + expect(validatePhrase('go ALSO', 'A')).toEqual({ valid: true }) + }) it('rejects unknown letter', () => { expect(validatePhrase('test', '1')).toEqual({ valid: false, message: 'Unknown letter' }) }) diff --git a/client/src/lib/morse.ts b/client/src/lib/morse.ts index 92c2377..f495a33 100644 --- a/client/src/lib/morse.ts +++ b/client/src/lib/morse.ts @@ -54,6 +54,8 @@ export const DOT_WORDS = [ 'pay','put','raw','sad','shy','son','tap','tin','toe','toy','two','use', 'way','you','aim','air','ask','bit','cut','dry','fun','god','had','hit', 'its','law','log','lot','mad','mix','net','not','odd','pet','row','she', + 'up','urn','us','ore','our','oar','oh','ow','ox','nod','nap','nil', + 'nor','dip','dig','dug','den','did','dam','hub','hug','hum','hen', ] export const DASH_WORDS = [ @@ -88,19 +90,29 @@ export const DASH_WORDS = [ 'weed','week','well','went','wide','wife','wild','will','wind','wine', 'wing','wire','wise','wish','wolf','wood','wool','word','work','worn', 'yarn','yell','zone','zoom', + 'oath','once','only','open','ours','over','oven', + 'unit','upon','urge','used', ] +function pickRandom