Skip to content

Commit fdb39a8

Browse files
committed
feat(Citation Generator): Add Vancouver Style
Fix #197
1 parent 50ffafc commit fdb39a8

File tree

4 files changed

+150
-7
lines changed

4 files changed

+150
-7
lines changed

locales/en.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3686,6 +3686,7 @@ tools:
36863686
placeholder-e-g-https-example-com: e.g. https://example.com
36873687
label-citation-style: Citation Style
36883688
title-generated-citation: Generated Citation
3689+
label-vancouver: Vancouver
36893690
cookies-parser:
36903691
title: Cookies Parser
36913692
description: Parse Cookie HTTP Header
Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
import { describe, expect, it } from 'vitest';
2+
3+
import { formatVancouverCitation } from './citation-generator.service'; // adjust path as needed
4+
5+
describe('formatVancouverCitation', () => {
6+
it('formats a single author with initials', () => {
7+
const entry = {
8+
authors: [{ first: 'John', last: 'Doe' }],
9+
year: '2021',
10+
title: 'Sample Title',
11+
publisher: 'Publisher',
12+
url: 'https://example.com',
13+
};
14+
expect(formatVancouverCitation(entry))
15+
.toBe('Doe J. Sample Title. Publisher; 2021. Available from: https://example.com');
16+
});
17+
18+
it('formats multiple authors correctly', () => {
19+
const entry = {
20+
authors: [
21+
{ first: 'John', last: 'Doe' },
22+
{ first: 'Jane', last: 'Smith' },
23+
],
24+
year: '2020',
25+
title: 'Multi Author Work',
26+
publisher: 'TechPress',
27+
};
28+
expect(formatVancouverCitation(entry))
29+
.toBe('Doe J, Smith J. Multi Author Work. TechPress; 2020.');
30+
});
31+
32+
it('uses et al. when more than 6 authors', () => {
33+
const entry = {
34+
authors: [
35+
{ first: 'A', last: 'One' },
36+
{ first: 'B', last: 'Two' },
37+
{ first: 'C', last: 'Three' },
38+
{ first: 'D', last: 'Four' },
39+
{ first: 'E', last: 'Five' },
40+
{ first: 'F', last: 'Six' },
41+
{ first: 'G', last: 'Seven' },
42+
],
43+
year: '2019',
44+
title: 'Big Team Paper',
45+
publisher: 'SciencePub',
46+
};
47+
expect(formatVancouverCitation(entry))
48+
.toBe('One A, Two B, Three C, Four D, Five E, Six F, et al. Big Team Paper. SciencePub; 2019.');
49+
});
50+
51+
it('handles multiple initials in first name', () => {
52+
const entry = {
53+
authors: [{ first: 'John Michael', last: 'Doe' }],
54+
title: 'Initials Test',
55+
};
56+
expect(formatVancouverCitation(entry))
57+
.toBe('Doe JM. Initials Test.');
58+
});
59+
60+
it('falls back to Anonymous if no authors', () => {
61+
const entry = {
62+
title: 'No Author Work',
63+
year: '2022',
64+
};
65+
expect(formatVancouverCitation(entry))
66+
.toBe('Anonymous. No Author Work. 2022.');
67+
});
68+
69+
it('handles missing title gracefully', () => {
70+
const entry = {
71+
authors: [{ first: 'Jane', last: 'Smith' }],
72+
year: '2023',
73+
};
74+
expect(formatVancouverCitation(entry))
75+
.toBe('Smith J. [No title]. 2023.');
76+
});
77+
78+
it('handles missing publisher and year', () => {
79+
const entry = {
80+
authors: [{ first: 'Jane', last: 'Smith' }],
81+
title: 'Untimed Work',
82+
};
83+
expect(formatVancouverCitation(entry))
84+
.toBe('Smith J. Untimed Work.');
85+
});
86+
});
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
interface Author { first?: string; last?: string }
2+
interface CitationInput {
3+
authors?: Author[]
4+
year?: string
5+
title?: string
6+
publisher?: string
7+
url?: string
8+
}
9+
10+
export function formatVancouverCitation(entry: CitationInput): string {
11+
const formatAuthor = (author: Author): string => {
12+
if (!author.last) {
13+
return '';
14+
}
15+
const initials = (author.first || '')
16+
.split(/\s+/)
17+
.map(name => name.charAt(0).toUpperCase())
18+
.join('');
19+
return `${author.last} ${initials}`;
20+
};
21+
22+
const authors = Array.isArray(entry.authors) ? entry.authors.map(formatAuthor).filter(Boolean) : [];
23+
let authorStr = 'Anonymous';
24+
if (authors.length > 0) {
25+
authorStr = authors.length > 6
26+
? `${authors.slice(0, 6).join(', ')}, et al`
27+
: authors.join(', ');
28+
}
29+
30+
const title = entry.title?.trim() || '[No title]';
31+
const publisher = entry.publisher?.trim();
32+
const year = entry.year?.trim();
33+
const url = entry.url?.trim();
34+
35+
let citation = `${authorStr}. ${title}.`;
36+
if (publisher) {
37+
citation += ` ${publisher};`;
38+
}
39+
if (year) {
40+
citation += ` ${year}.`;
41+
}
42+
if (url) {
43+
citation += ` Available from: ${url}`;
44+
}
45+
46+
return citation;
47+
}

src/tools/citation-generator/citation-generator.vue

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
import { useI18n } from 'vue-i18n';
33
import { ref } from 'vue';
44
import { APA, MLA } from 'citation-formatter';
5+
import { formatVancouverCitation } from './citation-generator.service';
56
67
const { t } = useI18n();
78
@@ -25,14 +26,21 @@ const formattedCitation = computed(() => {
2526
|| !citationData.value.year
2627
|| !authors.length
2728
) { return '### Please fill Title, Publisher, Year and authors'; }
29+
30+
const citationInData = {
31+
authors,
32+
title: citationData.value.title,
33+
publisher: citationData.value.publisher,
34+
year: citationData.value.year.toString(),
35+
url: citationData.value.url,
36+
};
37+
38+
if (style.value === 'vancouver') {
39+
return formatVancouverCitation(citationInData);
40+
}
2841
return (style.value === 'apa' ? APA : MLA)([
29-
{
30-
authors,
31-
title: citationData.value.title,
32-
publisher: citationData.value.publisher,
33-
year: citationData.value.year,
34-
url: citationData.value.url,
35-
}]);
42+
citationInData,
43+
]);
3644
}
3745
catch (e: any) {
3846
return e.toString();
@@ -72,6 +80,7 @@ const formattedCitation = computed(() => {
7280
:options="[
7381
{ label: t('tools.citation-generator.texts.label-apa'), value: 'apa' },
7482
{ label: t('tools.citation-generator.texts.label-mla'), value: 'mla' },
83+
{ label: t('tools.citation-generator.texts.label-vancouver'), value: 'vancouver' },
7584
]"
7685
/>
7786
</n-form-item>

0 commit comments

Comments
 (0)