@uniweb/scholar 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,352 @@
1
+ /**
2
+ * APA 7th Edition Reference Formatter
3
+ *
4
+ * Formats references according to APA 7th edition guidelines.
5
+ *
6
+ * @module @uniweb/scholar/bibliography/formatters/apa
7
+ */
8
+
9
+ import { formatApaAuthors, parseAuthorString } from '../utils/authors.js'
10
+ import { formatApaDate, getYear } from '../utils/dates.js'
11
+
12
+ /**
13
+ * Format a journal article in APA style
14
+ *
15
+ * @param {Object} pub - Publication data
16
+ * @returns {string}
17
+ */
18
+ function formatArticle(pub) {
19
+ const parts = []
20
+
21
+ // Authors
22
+ const authors = Array.isArray(pub.authors)
23
+ ? pub.authors
24
+ : parseAuthorString(pub.authors || pub.author)
25
+ if (authors.length) {
26
+ parts.push(formatApaAuthors(authors))
27
+ }
28
+
29
+ // Year
30
+ const year = getYear(pub.year || pub.date)
31
+ parts.push(`(${year || 'n.d.'}).`)
32
+
33
+ // Title
34
+ if (pub.title) {
35
+ parts.push(`${pub.title}.`)
36
+ }
37
+
38
+ // Journal (italicized in actual rendering)
39
+ if (pub.journal) {
40
+ let journalPart = pub.journal
41
+ if (pub.volume) {
42
+ journalPart += `, ${pub.volume}`
43
+ if (pub.issue) {
44
+ journalPart += `(${pub.issue})`
45
+ }
46
+ }
47
+ if (pub.pages) {
48
+ journalPart += `, ${pub.pages}`
49
+ }
50
+ parts.push(`${journalPart}.`)
51
+ }
52
+
53
+ // DOI
54
+ if (pub.doi) {
55
+ const doi = pub.doi.startsWith('http')
56
+ ? pub.doi
57
+ : `https://doi.org/${pub.doi}`
58
+ parts.push(doi)
59
+ }
60
+
61
+ return parts.join(' ')
62
+ }
63
+
64
+ /**
65
+ * Format a book in APA style
66
+ *
67
+ * @param {Object} pub - Publication data
68
+ * @returns {string}
69
+ */
70
+ function formatBook(pub) {
71
+ const parts = []
72
+
73
+ // Authors or editors
74
+ const authors = Array.isArray(pub.authors)
75
+ ? pub.authors
76
+ : parseAuthorString(pub.authors || pub.author)
77
+ const editors = Array.isArray(pub.editors)
78
+ ? pub.editors
79
+ : parseAuthorString(pub.editors || pub.editor)
80
+
81
+ if (authors.length) {
82
+ parts.push(formatApaAuthors(authors))
83
+ } else if (editors.length) {
84
+ parts.push(`${formatApaAuthors(editors)} (Ed${editors.length > 1 ? 's' : ''}).`)
85
+ }
86
+
87
+ // Year
88
+ const year = getYear(pub.year || pub.date)
89
+ parts.push(`(${year || 'n.d.'}).`)
90
+
91
+ // Title (italicized in actual rendering)
92
+ if (pub.title) {
93
+ let title = pub.title
94
+ if (pub.edition && pub.edition !== '1') {
95
+ title += ` (${pub.edition} ed.)`
96
+ }
97
+ parts.push(`${title}.`)
98
+ }
99
+
100
+ // Publisher
101
+ if (pub.publisher) {
102
+ parts.push(`${pub.publisher}.`)
103
+ }
104
+
105
+ // DOI or URL
106
+ if (pub.doi) {
107
+ const doi = pub.doi.startsWith('http')
108
+ ? pub.doi
109
+ : `https://doi.org/${pub.doi}`
110
+ parts.push(doi)
111
+ } else if (pub.url) {
112
+ parts.push(pub.url)
113
+ }
114
+
115
+ return parts.join(' ')
116
+ }
117
+
118
+ /**
119
+ * Format a book chapter in APA style
120
+ *
121
+ * @param {Object} pub - Publication data
122
+ * @returns {string}
123
+ */
124
+ function formatInBook(pub) {
125
+ const parts = []
126
+
127
+ // Chapter authors
128
+ const authors = Array.isArray(pub.authors)
129
+ ? pub.authors
130
+ : parseAuthorString(pub.authors || pub.author)
131
+ if (authors.length) {
132
+ parts.push(formatApaAuthors(authors))
133
+ }
134
+
135
+ // Year
136
+ const year = getYear(pub.year || pub.date)
137
+ parts.push(`(${year || 'n.d.'}).`)
138
+
139
+ // Chapter title
140
+ if (pub.title) {
141
+ parts.push(`${pub.title}.`)
142
+ }
143
+
144
+ // Book editors and title
145
+ const editors = Array.isArray(pub.editors)
146
+ ? pub.editors
147
+ : parseAuthorString(pub.editors || pub.editor)
148
+ if (editors.length || pub.bookTitle) {
149
+ let bookPart = 'In'
150
+ if (editors.length) {
151
+ bookPart += ` ${formatApaAuthors(editors)} (Ed${editors.length > 1 ? 's' : ''}),`
152
+ }
153
+ if (pub.bookTitle) {
154
+ bookPart += ` ${pub.bookTitle}`
155
+ }
156
+ if (pub.pages) {
157
+ bookPart += ` (pp. ${pub.pages})`
158
+ }
159
+ parts.push(`${bookPart}.`)
160
+ }
161
+
162
+ // Publisher
163
+ if (pub.publisher) {
164
+ parts.push(`${pub.publisher}.`)
165
+ }
166
+
167
+ // DOI
168
+ if (pub.doi) {
169
+ const doi = pub.doi.startsWith('http')
170
+ ? pub.doi
171
+ : `https://doi.org/${pub.doi}`
172
+ parts.push(doi)
173
+ }
174
+
175
+ return parts.join(' ')
176
+ }
177
+
178
+ /**
179
+ * Format conference proceedings in APA style
180
+ *
181
+ * @param {Object} pub - Publication data
182
+ * @returns {string}
183
+ */
184
+ function formatConference(pub) {
185
+ const parts = []
186
+
187
+ // Authors
188
+ const authors = Array.isArray(pub.authors)
189
+ ? pub.authors
190
+ : parseAuthorString(pub.authors || pub.author)
191
+ if (authors.length) {
192
+ parts.push(formatApaAuthors(authors))
193
+ }
194
+
195
+ // Year
196
+ const year = getYear(pub.year || pub.date)
197
+ parts.push(`(${year || 'n.d.'}).`)
198
+
199
+ // Title
200
+ if (pub.title) {
201
+ parts.push(`${pub.title}.`)
202
+ }
203
+
204
+ // Conference/Proceedings
205
+ if (pub.booktitle || pub.conference) {
206
+ let confPart = `In ${pub.booktitle || pub.conference}`
207
+ if (pub.pages) {
208
+ confPart += ` (pp. ${pub.pages})`
209
+ }
210
+ parts.push(`${confPart}.`)
211
+ }
212
+
213
+ // Publisher or location
214
+ if (pub.publisher) {
215
+ parts.push(`${pub.publisher}.`)
216
+ } else if (pub.address || pub.location) {
217
+ parts.push(`${pub.address || pub.location}.`)
218
+ }
219
+
220
+ // DOI
221
+ if (pub.doi) {
222
+ const doi = pub.doi.startsWith('http')
223
+ ? pub.doi
224
+ : `https://doi.org/${pub.doi}`
225
+ parts.push(doi)
226
+ }
227
+
228
+ return parts.join(' ')
229
+ }
230
+
231
+ /**
232
+ * Format a website/webpage in APA style
233
+ *
234
+ * @param {Object} pub - Publication data
235
+ * @returns {string}
236
+ */
237
+ function formatWebsite(pub) {
238
+ const parts = []
239
+
240
+ // Authors or organization
241
+ const authors = Array.isArray(pub.authors)
242
+ ? pub.authors
243
+ : parseAuthorString(pub.authors || pub.author)
244
+ if (authors.length) {
245
+ parts.push(formatApaAuthors(authors))
246
+ } else if (pub.organization) {
247
+ parts.push(pub.organization)
248
+ }
249
+
250
+ // Date
251
+ const date = formatApaDate(pub.date || pub.year)
252
+ parts.push(`(${date}).`)
253
+
254
+ // Title
255
+ if (pub.title) {
256
+ parts.push(`${pub.title}.`)
257
+ }
258
+
259
+ // Site name
260
+ if (pub.siteName && pub.siteName !== pub.organization) {
261
+ parts.push(`${pub.siteName}.`)
262
+ }
263
+
264
+ // URL
265
+ if (pub.url) {
266
+ parts.push(pub.url)
267
+ }
268
+
269
+ return parts.join(' ')
270
+ }
271
+
272
+ /**
273
+ * Format a thesis/dissertation in APA style
274
+ *
275
+ * @param {Object} pub - Publication data
276
+ * @returns {string}
277
+ */
278
+ function formatThesis(pub) {
279
+ const parts = []
280
+
281
+ // Author
282
+ const authors = Array.isArray(pub.authors)
283
+ ? pub.authors
284
+ : parseAuthorString(pub.authors || pub.author)
285
+ if (authors.length) {
286
+ parts.push(formatApaAuthors(authors))
287
+ }
288
+
289
+ // Year
290
+ const year = getYear(pub.year || pub.date)
291
+ parts.push(`(${year || 'n.d.'}).`)
292
+
293
+ // Title (italicized)
294
+ if (pub.title) {
295
+ parts.push(`${pub.title}`)
296
+ }
297
+
298
+ // Thesis type and institution
299
+ const type = pub.type || 'Doctoral dissertation'
300
+ if (pub.school || pub.institution) {
301
+ parts.push(`[${type}, ${pub.school || pub.institution}].`)
302
+ } else {
303
+ parts.push(`[${type}].`)
304
+ }
305
+
306
+ // URL or database
307
+ if (pub.url) {
308
+ parts.push(pub.url)
309
+ }
310
+
311
+ return parts.join(' ')
312
+ }
313
+
314
+ /**
315
+ * Format a reference in APA 7th edition style
316
+ *
317
+ * @param {Object} pub - Publication data
318
+ * @param {Object} [options] - Formatting options
319
+ * @returns {string}
320
+ */
321
+ export function formatApa(pub, options = {}) {
322
+ const type = (pub.type || pub.entryType || 'article').toLowerCase()
323
+
324
+ switch (type) {
325
+ case 'article':
326
+ case 'journal':
327
+ return formatArticle(pub)
328
+ case 'book':
329
+ return formatBook(pub)
330
+ case 'inbook':
331
+ case 'incollection':
332
+ case 'chapter':
333
+ return formatInBook(pub)
334
+ case 'inproceedings':
335
+ case 'conference':
336
+ case 'proceedings':
337
+ return formatConference(pub)
338
+ case 'webpage':
339
+ case 'website':
340
+ case 'online':
341
+ return formatWebsite(pub)
342
+ case 'thesis':
343
+ case 'phdthesis':
344
+ case 'mastersthesis':
345
+ return formatThesis(pub)
346
+ default:
347
+ // Generic format
348
+ return formatArticle(pub)
349
+ }
350
+ }
351
+
352
+ export default formatApa
@@ -0,0 +1,339 @@
1
+ /**
2
+ * Chicago Style (Author-Date) Reference Formatter
3
+ *
4
+ * Formats references according to Chicago Manual of Style 17th edition
5
+ * author-date format.
6
+ *
7
+ * @module @uniweb/scholar/bibliography/formatters/chicago
8
+ */
9
+
10
+ import { formatChicagoAuthors, parseAuthorString } from '../utils/authors.js'
11
+ import { formatChicagoDate, getYear } from '../utils/dates.js'
12
+
13
+ /**
14
+ * Format a journal article in Chicago style
15
+ *
16
+ * @param {Object} pub - Publication data
17
+ * @returns {string}
18
+ */
19
+ function formatArticle(pub) {
20
+ const parts = []
21
+
22
+ // Authors
23
+ const authors = Array.isArray(pub.authors)
24
+ ? pub.authors
25
+ : parseAuthorString(pub.authors || pub.author)
26
+ if (authors.length) {
27
+ parts.push(`${formatChicagoAuthors(authors)}.`)
28
+ }
29
+
30
+ // Year
31
+ const year = getYear(pub.year || pub.date)
32
+ if (year) {
33
+ parts.push(`${year}.`)
34
+ }
35
+
36
+ // Title in quotes
37
+ if (pub.title) {
38
+ parts.push(`"${pub.title}."`)
39
+ }
40
+
41
+ // Journal (italicized)
42
+ if (pub.journal) {
43
+ let journalPart = pub.journal
44
+ if (pub.volume) {
45
+ journalPart += ` ${pub.volume}`
46
+ if (pub.issue) {
47
+ journalPart += `, no. ${pub.issue}`
48
+ }
49
+ }
50
+ if (pub.pages) {
51
+ journalPart += `: ${pub.pages}`
52
+ }
53
+ parts.push(`${journalPart}.`)
54
+ }
55
+
56
+ // DOI
57
+ if (pub.doi) {
58
+ const doi = pub.doi.startsWith('http')
59
+ ? pub.doi
60
+ : `https://doi.org/${pub.doi}`
61
+ parts.push(doi)
62
+ }
63
+
64
+ return parts.join(' ')
65
+ }
66
+
67
+ /**
68
+ * Format a book in Chicago style
69
+ *
70
+ * @param {Object} pub - Publication data
71
+ * @returns {string}
72
+ */
73
+ function formatBook(pub) {
74
+ const parts = []
75
+
76
+ // Authors or editors
77
+ const authors = Array.isArray(pub.authors)
78
+ ? pub.authors
79
+ : parseAuthorString(pub.authors || pub.author)
80
+ const editors = Array.isArray(pub.editors)
81
+ ? pub.editors
82
+ : parseAuthorString(pub.editors || pub.editor)
83
+
84
+ if (authors.length) {
85
+ parts.push(`${formatChicagoAuthors(authors)}.`)
86
+ } else if (editors.length) {
87
+ parts.push(
88
+ `${formatChicagoAuthors(editors)}, ed${editors.length > 1 ? 's' : ''}.`
89
+ )
90
+ }
91
+
92
+ // Year
93
+ const year = getYear(pub.year || pub.date)
94
+ if (year) {
95
+ parts.push(`${year}.`)
96
+ }
97
+
98
+ // Title (italicized)
99
+ if (pub.title) {
100
+ let title = pub.title
101
+ if (pub.edition && pub.edition !== '1') {
102
+ title += `. ${pub.edition} ed`
103
+ }
104
+ parts.push(`${title}.`)
105
+ }
106
+
107
+ // Place and publisher
108
+ if (pub.address && pub.publisher) {
109
+ parts.push(`${pub.address}: ${pub.publisher}.`)
110
+ } else if (pub.publisher) {
111
+ parts.push(`${pub.publisher}.`)
112
+ }
113
+
114
+ return parts.join(' ')
115
+ }
116
+
117
+ /**
118
+ * Format a book chapter in Chicago style
119
+ *
120
+ * @param {Object} pub - Publication data
121
+ * @returns {string}
122
+ */
123
+ function formatInBook(pub) {
124
+ const parts = []
125
+
126
+ // Chapter authors
127
+ const authors = Array.isArray(pub.authors)
128
+ ? pub.authors
129
+ : parseAuthorString(pub.authors || pub.author)
130
+ if (authors.length) {
131
+ parts.push(`${formatChicagoAuthors(authors)}.`)
132
+ }
133
+
134
+ // Year
135
+ const year = getYear(pub.year || pub.date)
136
+ if (year) {
137
+ parts.push(`${year}.`)
138
+ }
139
+
140
+ // Chapter title in quotes
141
+ if (pub.title) {
142
+ parts.push(`"${pub.title}."`)
143
+ }
144
+
145
+ // Book title and editors
146
+ if (pub.bookTitle) {
147
+ let bookPart = `In ${pub.bookTitle}`
148
+ const editors = Array.isArray(pub.editors)
149
+ ? pub.editors
150
+ : parseAuthorString(pub.editors || pub.editor)
151
+ if (editors.length) {
152
+ bookPart += `, edited by ${formatChicagoAuthors(editors)}`
153
+ }
154
+ if (pub.pages) {
155
+ bookPart += `, ${pub.pages}`
156
+ }
157
+ parts.push(`${bookPart}.`)
158
+ }
159
+
160
+ // Place and publisher
161
+ if (pub.address && pub.publisher) {
162
+ parts.push(`${pub.address}: ${pub.publisher}.`)
163
+ } else if (pub.publisher) {
164
+ parts.push(`${pub.publisher}.`)
165
+ }
166
+
167
+ return parts.join(' ')
168
+ }
169
+
170
+ /**
171
+ * Format conference proceedings in Chicago style
172
+ *
173
+ * @param {Object} pub - Publication data
174
+ * @returns {string}
175
+ */
176
+ function formatConference(pub) {
177
+ const parts = []
178
+
179
+ // Authors
180
+ const authors = Array.isArray(pub.authors)
181
+ ? pub.authors
182
+ : parseAuthorString(pub.authors || pub.author)
183
+ if (authors.length) {
184
+ parts.push(`${formatChicagoAuthors(authors)}.`)
185
+ }
186
+
187
+ // Year
188
+ const year = getYear(pub.year || pub.date)
189
+ if (year) {
190
+ parts.push(`${year}.`)
191
+ }
192
+
193
+ // Title in quotes
194
+ if (pub.title) {
195
+ parts.push(`"${pub.title}."`)
196
+ }
197
+
198
+ // Conference name
199
+ if (pub.booktitle || pub.conference) {
200
+ let confPart = `Paper presented at ${pub.booktitle || pub.conference}`
201
+ if (pub.address || pub.location) {
202
+ confPart += `, ${pub.address || pub.location}`
203
+ }
204
+ parts.push(`${confPart}.`)
205
+ }
206
+
207
+ // DOI
208
+ if (pub.doi) {
209
+ const doi = pub.doi.startsWith('http')
210
+ ? pub.doi
211
+ : `https://doi.org/${pub.doi}`
212
+ parts.push(doi)
213
+ }
214
+
215
+ return parts.join(' ')
216
+ }
217
+
218
+ /**
219
+ * Format a website/webpage in Chicago style
220
+ *
221
+ * @param {Object} pub - Publication data
222
+ * @returns {string}
223
+ */
224
+ function formatWebsite(pub) {
225
+ const parts = []
226
+
227
+ // Authors or organization
228
+ const authors = Array.isArray(pub.authors)
229
+ ? pub.authors
230
+ : parseAuthorString(pub.authors || pub.author)
231
+ if (authors.length) {
232
+ parts.push(`${formatChicagoAuthors(authors)}.`)
233
+ } else if (pub.organization) {
234
+ parts.push(`${pub.organization}.`)
235
+ }
236
+
237
+ // Year
238
+ const year = getYear(pub.year || pub.date)
239
+ if (year) {
240
+ parts.push(`${year}.`)
241
+ }
242
+
243
+ // Title in quotes
244
+ if (pub.title) {
245
+ parts.push(`"${pub.title}."`)
246
+ }
247
+
248
+ // Site name
249
+ if (pub.siteName) {
250
+ parts.push(`${pub.siteName}.`)
251
+ }
252
+
253
+ // Access date and URL
254
+ if (pub.accessDate) {
255
+ parts.push(`Accessed ${formatChicagoDate(pub.accessDate)}.`)
256
+ }
257
+ if (pub.url) {
258
+ parts.push(pub.url)
259
+ }
260
+
261
+ return parts.join(' ')
262
+ }
263
+
264
+ /**
265
+ * Format a thesis/dissertation in Chicago style
266
+ *
267
+ * @param {Object} pub - Publication data
268
+ * @returns {string}
269
+ */
270
+ function formatThesis(pub) {
271
+ const parts = []
272
+
273
+ // Author
274
+ const authors = Array.isArray(pub.authors)
275
+ ? pub.authors
276
+ : parseAuthorString(pub.authors || pub.author)
277
+ if (authors.length) {
278
+ parts.push(`${formatChicagoAuthors(authors)}.`)
279
+ }
280
+
281
+ // Year
282
+ const year = getYear(pub.year || pub.date)
283
+ if (year) {
284
+ parts.push(`${year}.`)
285
+ }
286
+
287
+ // Title in quotes
288
+ if (pub.title) {
289
+ parts.push(`"${pub.title}."`)
290
+ }
291
+
292
+ // Type and institution
293
+ const type =
294
+ pub.type === 'mastersthesis' ? 'Master\'s thesis' : 'PhD diss.'
295
+ if (pub.school || pub.institution) {
296
+ parts.push(`${type}, ${pub.school || pub.institution}.`)
297
+ }
298
+
299
+ return parts.join(' ')
300
+ }
301
+
302
+ /**
303
+ * Format a reference in Chicago author-date style
304
+ *
305
+ * @param {Object} pub - Publication data
306
+ * @param {Object} [options] - Formatting options
307
+ * @returns {string}
308
+ */
309
+ export function formatChicago(pub, options = {}) {
310
+ const type = (pub.type || pub.entryType || 'article').toLowerCase()
311
+
312
+ switch (type) {
313
+ case 'article':
314
+ case 'journal':
315
+ return formatArticle(pub)
316
+ case 'book':
317
+ return formatBook(pub)
318
+ case 'inbook':
319
+ case 'incollection':
320
+ case 'chapter':
321
+ return formatInBook(pub)
322
+ case 'inproceedings':
323
+ case 'conference':
324
+ case 'proceedings':
325
+ return formatConference(pub)
326
+ case 'webpage':
327
+ case 'website':
328
+ case 'online':
329
+ return formatWebsite(pub)
330
+ case 'thesis':
331
+ case 'phdthesis':
332
+ case 'mastersthesis':
333
+ return formatThesis(pub)
334
+ default:
335
+ return formatArticle(pub)
336
+ }
337
+ }
338
+
339
+ export default formatChicago