File size: 2,370 Bytes
1749a26
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6ac1f78
1749a26
 
6ac1f78
 
 
 
 
 
 
 
 
1749a26
 
6ac1f78
1749a26
 
6ac1f78
 
 
1749a26
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
import { describe, it, expect } from 'vitest';
import { splitCitations } from './citations';

const REFS = [
  { id: 'r1', short: 'Carnall 2018', year: 2018, corpusMatch: true },
  { id: 'r2', short: 'Behroozi 2019', year: 2019, corpusMatch: false },
  { id: 'r3', short: 'Stark 2016', year: 2016, corpusMatch: true },
];
const IDX = {
  'carnall:2018': ['r1'],
  'behroozi:2019': ['r2'],
  'stark:2016': ['r3'],
};

describe('splitCitations', () => {
  it('narrative cite: Carnall et al. (2018)', () => {
    const segs = splitCitations('From Carnall et al. (2018) we know this.', IDX, REFS);
    const cite = segs.find((s) => s.t === 'cite');
    expect(cite).toBeTruthy();
    expect(cite.refs[0].id).toBe('r1');
    expect(cite.refs[0].corpusMatch).toBe(true);
  });

  it('parenthetical multi-cite: each unit is its own cite segment', () => {
    const segs = splitCitations('Results (Behroozi et al. 2019; Stark 2016) agree.', IDX, REFS);
    const cites = segs.filter((s) => s.t === 'cite');
    // Two separate cite segments, not one combined
    expect(cites).toHaveLength(2);
    expect(cites[0].refs[0].id).toBe('r2');
    expect(cites[1].refs[0].id).toBe('r3');
    // Surrounding punctuation preserved as text
    const texts = segs.filter((s) => s.t === 'text').map((s) => s.s);
    expect(texts.some((s) => s.includes('('))).toBe(true);
    expect(texts.some((s) => s.includes(')'))).toBe(true);
    expect(texts.some((s) => s.includes(';'))).toBe(true);
  });

  it('unmatched cite gets a cite span with empty refs (for visual styling)', () => {
    const segs = splitCitations('See Hubble (1929) for early evidence.', IDX, REFS);
    const cite = segs.find((s) => s.t === 'cite');
    expect(cite).toBeTruthy();
    expect(cite.s).toContain('Hubble');
    expect(cite.refs).toHaveLength(0);
  });

  it('no citations → single text segment', () => {
    const segs = splitCitations('No references here at all.', IDX, REFS);
    expect(segs).toHaveLength(1);
    expect(segs[0].t).toBe('text');
  });

  it('surname & Other (year) narrative form', () => {
    const segs = splitCitations('Carnall & McLure (2018) showed this.', IDX, REFS);
    const cite = segs.find((s) => s.t === 'cite');
    expect(cite?.refs[0].id).toBe('r1');
  });

  it('empty string returns empty array', () => {
    expect(splitCitations('', IDX, REFS)).toEqual([]);
  });
});