@ncukondo/slide-generation 0.2.5 → 0.4.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.
- package/README.md +46 -0
- package/README_ja.md +46 -0
- package/dist/cli/index.js +1509 -239
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +21 -7
- package/dist/index.js +264 -91
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/templates/layouts/image-text.yaml +4 -2
- package/templates/layouts/three-column.yaml +4 -2
- package/templates/layouts/two-column.yaml +8 -4
- package/templates/special/bibliography.yaml +4 -4
package/dist/index.d.ts
CHANGED
|
@@ -598,7 +598,7 @@ declare class ReferenceManager {
|
|
|
598
598
|
*/
|
|
599
599
|
getById(id: string): Promise<CSLItem | null>;
|
|
600
600
|
/**
|
|
601
|
-
* Get multiple references by IDs
|
|
601
|
+
* Get multiple references by IDs using ref export for better performance
|
|
602
602
|
*/
|
|
603
603
|
getByIds(ids: string[]): Promise<Map<string, CSLItem>>;
|
|
604
604
|
private execCommand;
|
|
@@ -624,7 +624,13 @@ interface FormatterConfig {
|
|
|
624
624
|
declare class CitationFormatter {
|
|
625
625
|
private manager;
|
|
626
626
|
private config;
|
|
627
|
+
private availabilityChecked;
|
|
628
|
+
private isAvailable;
|
|
627
629
|
constructor(manager: ReferenceManager, config?: FormatterConfig);
|
|
630
|
+
/**
|
|
631
|
+
* Check if reference-manager is available (cached)
|
|
632
|
+
*/
|
|
633
|
+
private checkAvailability;
|
|
628
634
|
/**
|
|
629
635
|
* Format an inline citation
|
|
630
636
|
* e.g., "(Smith et al., 2024; PMID: 12345678)"
|
|
@@ -644,13 +650,7 @@ declare class CitationFormatter {
|
|
|
644
650
|
*/
|
|
645
651
|
generateBibliography(ids: string[], sort?: 'author' | 'year' | 'citation-order'): Promise<string[]>;
|
|
646
652
|
private formatInlineItem;
|
|
647
|
-
private formatFullItem;
|
|
648
653
|
private formatAuthorInline;
|
|
649
|
-
private formatAuthorsFull;
|
|
650
|
-
private isJapaneseAuthors;
|
|
651
|
-
private getFirstAuthorFamily;
|
|
652
|
-
private getYear;
|
|
653
|
-
private getIdentifier;
|
|
654
654
|
}
|
|
655
655
|
|
|
656
656
|
/**
|
|
@@ -966,6 +966,7 @@ declare class Pipeline {
|
|
|
966
966
|
private referenceManager;
|
|
967
967
|
private citationExtractor;
|
|
968
968
|
private citationFormatter;
|
|
969
|
+
private bibliographyGenerator;
|
|
969
970
|
private transformer;
|
|
970
971
|
private renderer;
|
|
971
972
|
private warnings;
|
|
@@ -1006,6 +1007,19 @@ declare class Pipeline {
|
|
|
1006
1007
|
* Stage 5: Render the final Marp markdown
|
|
1007
1008
|
*/
|
|
1008
1009
|
private render;
|
|
1010
|
+
/**
|
|
1011
|
+
* Process bibliography slides with autoGenerate: true
|
|
1012
|
+
* Populates references array from collected citations
|
|
1013
|
+
*/
|
|
1014
|
+
private processBibliography;
|
|
1015
|
+
/**
|
|
1016
|
+
* Format authors for template-compatible format
|
|
1017
|
+
*/
|
|
1018
|
+
private formatAuthorsForTemplate;
|
|
1019
|
+
/**
|
|
1020
|
+
* Get year from CSL item
|
|
1021
|
+
*/
|
|
1022
|
+
private getYear;
|
|
1009
1023
|
}
|
|
1010
1024
|
|
|
1011
1025
|
/**
|
package/dist/index.js
CHANGED
|
@@ -918,20 +918,20 @@ var ReferenceManager = class {
|
|
|
918
918
|
return items[0] || null;
|
|
919
919
|
}
|
|
920
920
|
/**
|
|
921
|
-
* Get multiple references by IDs
|
|
921
|
+
* Get multiple references by IDs using ref export for better performance
|
|
922
922
|
*/
|
|
923
923
|
async getByIds(ids) {
|
|
924
924
|
if (ids.length === 0) {
|
|
925
925
|
return /* @__PURE__ */ new Map();
|
|
926
926
|
}
|
|
927
|
-
const
|
|
928
|
-
const
|
|
929
|
-
|
|
927
|
+
const idsArg = ids.map((id) => `"${id}"`).join(" ");
|
|
928
|
+
const result = await this.execCommand(
|
|
929
|
+
`${this.command} export ${idsArg}`
|
|
930
|
+
);
|
|
931
|
+
const items = this.parseJSON(result);
|
|
930
932
|
const map = /* @__PURE__ */ new Map();
|
|
931
|
-
for (const item of
|
|
932
|
-
|
|
933
|
-
map.set(item.id, item);
|
|
934
|
-
}
|
|
933
|
+
for (const item of items) {
|
|
934
|
+
map.set(item.id, item);
|
|
935
935
|
}
|
|
936
936
|
return map;
|
|
937
937
|
}
|
|
@@ -1075,6 +1075,82 @@ var CitationExtractor = class {
|
|
|
1075
1075
|
}
|
|
1076
1076
|
};
|
|
1077
1077
|
|
|
1078
|
+
// src/references/utils.ts
|
|
1079
|
+
var JAPANESE_PATTERN = /[\u3040-\u309F\u30A0-\u30FF\u4E00-\u9FAF]/;
|
|
1080
|
+
function isJapaneseAuthors(authors) {
|
|
1081
|
+
if (!authors || authors.length === 0) {
|
|
1082
|
+
return false;
|
|
1083
|
+
}
|
|
1084
|
+
return JAPANESE_PATTERN.test(authors[0].family);
|
|
1085
|
+
}
|
|
1086
|
+
function getYear(item) {
|
|
1087
|
+
const dateParts = item.issued?.["date-parts"];
|
|
1088
|
+
if (dateParts && dateParts[0] && dateParts[0][0]) {
|
|
1089
|
+
return dateParts[0][0];
|
|
1090
|
+
}
|
|
1091
|
+
return 0;
|
|
1092
|
+
}
|
|
1093
|
+
function getIdentifier(item) {
|
|
1094
|
+
if (item.PMID) {
|
|
1095
|
+
return `PMID: ${item.PMID}`;
|
|
1096
|
+
}
|
|
1097
|
+
if (item.DOI) {
|
|
1098
|
+
return `DOI: ${item.DOI}`;
|
|
1099
|
+
}
|
|
1100
|
+
return null;
|
|
1101
|
+
}
|
|
1102
|
+
function getFirstAuthorFamily(item) {
|
|
1103
|
+
return item.author?.[0]?.family || "";
|
|
1104
|
+
}
|
|
1105
|
+
function formatAuthorsFull(authors, isJapanese) {
|
|
1106
|
+
if (!authors || authors.length === 0) {
|
|
1107
|
+
return "Unknown";
|
|
1108
|
+
}
|
|
1109
|
+
if (isJapanese) {
|
|
1110
|
+
return authors.map((a) => `${a.family}${a.given || ""}`).join(", ");
|
|
1111
|
+
}
|
|
1112
|
+
if (authors.length === 1) {
|
|
1113
|
+
const a = authors[0];
|
|
1114
|
+
const initial = a.given ? `${a.given.charAt(0)}.` : "";
|
|
1115
|
+
return `${a.family}, ${initial}`;
|
|
1116
|
+
}
|
|
1117
|
+
const formatted = authors.map((a, i) => {
|
|
1118
|
+
const initial = a.given ? `${a.given.charAt(0)}.` : "";
|
|
1119
|
+
if (i === authors.length - 1) {
|
|
1120
|
+
return `& ${a.family}, ${initial}`;
|
|
1121
|
+
}
|
|
1122
|
+
return `${a.family}, ${initial}`;
|
|
1123
|
+
});
|
|
1124
|
+
return formatted.join(", ").replace(", &", ", &");
|
|
1125
|
+
}
|
|
1126
|
+
function formatFullEntry(item) {
|
|
1127
|
+
const parts = [];
|
|
1128
|
+
const japanese = isJapaneseAuthors(item.author);
|
|
1129
|
+
const authors = formatAuthorsFull(item.author, japanese);
|
|
1130
|
+
parts.push(authors);
|
|
1131
|
+
const year = getYear(item);
|
|
1132
|
+
parts.push(`(${year}).`);
|
|
1133
|
+
if (item.title) {
|
|
1134
|
+
parts.push(`${item.title}.`);
|
|
1135
|
+
}
|
|
1136
|
+
if (item["container-title"]) {
|
|
1137
|
+
const journal = japanese ? item["container-title"] : `*${item["container-title"]}*`;
|
|
1138
|
+
let location = "";
|
|
1139
|
+
if (item.volume) {
|
|
1140
|
+
location = item.issue ? `${item.volume}(${item.issue})` : item.volume;
|
|
1141
|
+
}
|
|
1142
|
+
if (item.page) {
|
|
1143
|
+
location = location ? `${location}, ${item.page}` : item.page;
|
|
1144
|
+
}
|
|
1145
|
+
parts.push(location ? `${journal}, ${location}.` : `${journal}.`);
|
|
1146
|
+
}
|
|
1147
|
+
const identifier = getIdentifier(item);
|
|
1148
|
+
if (identifier) {
|
|
1149
|
+
parts.push(identifier);
|
|
1150
|
+
}
|
|
1151
|
+
return parts.join(" ");
|
|
1152
|
+
}
|
|
1153
|
+
|
|
1078
1154
|
// src/references/formatter.ts
|
|
1079
1155
|
var DEFAULT_CONFIG = {
|
|
1080
1156
|
author: {
|
|
@@ -1089,7 +1165,6 @@ var DEFAULT_CONFIG = {
|
|
|
1089
1165
|
multiSep: "), ("
|
|
1090
1166
|
}
|
|
1091
1167
|
};
|
|
1092
|
-
var JAPANESE_PATTERN = /[\u3040-\u309F\u30A0-\u30FF\u4E00-\u9FAF]/;
|
|
1093
1168
|
var CITATION_BRACKET_PATTERN2 = /\[(@[\w-]+(?:,\s*[^;\]]+)?(?:;\s*@[\w-]+(?:,\s*[^;\]]+)?)*)\]/g;
|
|
1094
1169
|
var SINGLE_CITATION_PATTERN2 = /@([\w-]+)(?:,\s*([^;\]]+))?/g;
|
|
1095
1170
|
var CitationFormatter = class {
|
|
@@ -1101,6 +1176,18 @@ var CitationFormatter = class {
|
|
|
1101
1176
|
};
|
|
1102
1177
|
}
|
|
1103
1178
|
config;
|
|
1179
|
+
availabilityChecked = false;
|
|
1180
|
+
isAvailable = false;
|
|
1181
|
+
/**
|
|
1182
|
+
* Check if reference-manager is available (cached)
|
|
1183
|
+
*/
|
|
1184
|
+
async checkAvailability() {
|
|
1185
|
+
if (!this.availabilityChecked) {
|
|
1186
|
+
this.isAvailable = await this.manager.isAvailable();
|
|
1187
|
+
this.availabilityChecked = true;
|
|
1188
|
+
}
|
|
1189
|
+
return this.isAvailable;
|
|
1190
|
+
}
|
|
1104
1191
|
/**
|
|
1105
1192
|
* Format an inline citation
|
|
1106
1193
|
* e.g., "(Smith et al., 2024; PMID: 12345678)"
|
|
@@ -1120,13 +1207,16 @@ var CitationFormatter = class {
|
|
|
1120
1207
|
if (!item) {
|
|
1121
1208
|
return `[${id}]`;
|
|
1122
1209
|
}
|
|
1123
|
-
return
|
|
1210
|
+
return formatFullEntry(item);
|
|
1124
1211
|
}
|
|
1125
1212
|
/**
|
|
1126
1213
|
* Expand all citations in text
|
|
1127
1214
|
* e.g., "[@smith2024]" -> "(Smith et al., 2024; PMID: 12345678)"
|
|
1128
1215
|
*/
|
|
1129
1216
|
async expandCitations(text) {
|
|
1217
|
+
if (!await this.checkAvailability()) {
|
|
1218
|
+
return text;
|
|
1219
|
+
}
|
|
1130
1220
|
const ids = /* @__PURE__ */ new Set();
|
|
1131
1221
|
CITATION_BRACKET_PATTERN2.lastIndex = 0;
|
|
1132
1222
|
let match;
|
|
@@ -1181,117 +1271,102 @@ var CitationFormatter = class {
|
|
|
1181
1271
|
sortedItems = ids.map((id) => items.get(id)).filter((item) => item !== void 0);
|
|
1182
1272
|
} else if (sort === "author") {
|
|
1183
1273
|
sortedItems = [...items.values()].sort((a, b) => {
|
|
1184
|
-
const authorA =
|
|
1185
|
-
const authorB =
|
|
1274
|
+
const authorA = getFirstAuthorFamily(a);
|
|
1275
|
+
const authorB = getFirstAuthorFamily(b);
|
|
1186
1276
|
return authorA.localeCompare(authorB);
|
|
1187
1277
|
});
|
|
1188
1278
|
} else {
|
|
1189
1279
|
sortedItems = [...items.values()].sort((a, b) => {
|
|
1190
|
-
const yearA =
|
|
1191
|
-
const yearB =
|
|
1280
|
+
const yearA = getYear(a);
|
|
1281
|
+
const yearB = getYear(b);
|
|
1192
1282
|
return yearA - yearB;
|
|
1193
1283
|
});
|
|
1194
1284
|
}
|
|
1195
|
-
return sortedItems.map((item) =>
|
|
1285
|
+
return sortedItems.map((item) => formatFullEntry(item));
|
|
1196
1286
|
}
|
|
1197
1287
|
formatInlineItem(item) {
|
|
1198
1288
|
const author = this.formatAuthorInline(item.author);
|
|
1199
|
-
const year =
|
|
1200
|
-
const identifier =
|
|
1289
|
+
const year = getYear(item);
|
|
1290
|
+
const identifier = getIdentifier(item);
|
|
1201
1291
|
if (identifier) {
|
|
1202
1292
|
return `(${author}, ${year}; ${identifier})`;
|
|
1203
1293
|
}
|
|
1204
1294
|
return `(${author}, ${year})`;
|
|
1205
1295
|
}
|
|
1206
|
-
formatFullItem(item) {
|
|
1207
|
-
const parts = [];
|
|
1208
|
-
const isJapanese = this.isJapaneseAuthors(item.author);
|
|
1209
|
-
const authors = this.formatAuthorsFull(item.author, isJapanese);
|
|
1210
|
-
parts.push(authors);
|
|
1211
|
-
const year = this.getYear(item);
|
|
1212
|
-
parts.push(`(${year}).`);
|
|
1213
|
-
if (item.title) {
|
|
1214
|
-
parts.push(`${item.title}.`);
|
|
1215
|
-
}
|
|
1216
|
-
if (item["container-title"]) {
|
|
1217
|
-
const journal = isJapanese ? item["container-title"] : `*${item["container-title"]}*`;
|
|
1218
|
-
let location = "";
|
|
1219
|
-
if (item.volume) {
|
|
1220
|
-
location = item.issue ? `${item.volume}(${item.issue})` : item.volume;
|
|
1221
|
-
}
|
|
1222
|
-
if (item.page) {
|
|
1223
|
-
location = location ? `${location}, ${item.page}` : item.page;
|
|
1224
|
-
}
|
|
1225
|
-
parts.push(location ? `${journal}, ${location}.` : `${journal}.`);
|
|
1226
|
-
}
|
|
1227
|
-
const identifier = this.getIdentifier(item);
|
|
1228
|
-
if (identifier) {
|
|
1229
|
-
parts.push(identifier);
|
|
1230
|
-
}
|
|
1231
|
-
return parts.join(" ");
|
|
1232
|
-
}
|
|
1233
1296
|
formatAuthorInline(authors) {
|
|
1234
1297
|
if (!authors || authors.length === 0) {
|
|
1235
1298
|
return "Unknown";
|
|
1236
1299
|
}
|
|
1237
|
-
const
|
|
1300
|
+
const japanese = isJapaneseAuthors(authors);
|
|
1238
1301
|
const { etAl, etAlJa, separatorJa } = this.config.author;
|
|
1239
1302
|
const firstAuthor = authors[0];
|
|
1240
1303
|
if (authors.length === 1) {
|
|
1241
1304
|
return firstAuthor.family;
|
|
1242
1305
|
}
|
|
1243
1306
|
if (authors.length === 2) {
|
|
1244
|
-
const separator =
|
|
1307
|
+
const separator = japanese ? separatorJa : " & ";
|
|
1245
1308
|
return `${firstAuthor.family}${separator}${authors[1].family}`;
|
|
1246
1309
|
}
|
|
1247
|
-
const suffix =
|
|
1310
|
+
const suffix = japanese ? etAlJa : ` ${etAl}`;
|
|
1248
1311
|
return `${firstAuthor.family}${suffix}`;
|
|
1249
1312
|
}
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
}
|
|
1257
|
-
if (authors.length === 1) {
|
|
1258
|
-
const a = authors[0];
|
|
1259
|
-
const initial = a.given ? `${a.given.charAt(0)}.` : "";
|
|
1260
|
-
return `${a.family}, ${initial}`;
|
|
1261
|
-
}
|
|
1262
|
-
const formatted = authors.map((a, i) => {
|
|
1263
|
-
const initial = a.given ? `${a.given.charAt(0)}.` : "";
|
|
1264
|
-
if (i === authors.length - 1) {
|
|
1265
|
-
return `& ${a.family}, ${initial}`;
|
|
1266
|
-
}
|
|
1267
|
-
return `${a.family}, ${initial}`;
|
|
1268
|
-
});
|
|
1269
|
-
return formatted.join(", ").replace(", &", ", &");
|
|
1270
|
-
}
|
|
1271
|
-
isJapaneseAuthors(authors) {
|
|
1272
|
-
if (!authors || authors.length === 0) {
|
|
1273
|
-
return false;
|
|
1274
|
-
}
|
|
1275
|
-
return JAPANESE_PATTERN.test(authors[0].family);
|
|
1276
|
-
}
|
|
1277
|
-
getFirstAuthorFamily(item) {
|
|
1278
|
-
return item.author?.[0]?.family || "";
|
|
1313
|
+
};
|
|
1314
|
+
|
|
1315
|
+
// src/references/bibliography.ts
|
|
1316
|
+
var BibliographyGenerator = class {
|
|
1317
|
+
constructor(manager) {
|
|
1318
|
+
this.manager = manager;
|
|
1279
1319
|
}
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1320
|
+
/**
|
|
1321
|
+
* Generate bibliography entries from citation IDs
|
|
1322
|
+
*/
|
|
1323
|
+
async generate(citationIds, options = {}) {
|
|
1324
|
+
const { sort = "citation-order" } = options;
|
|
1325
|
+
if (citationIds.length === 0) {
|
|
1326
|
+
return { entries: [], items: [], missing: [] };
|
|
1327
|
+
}
|
|
1328
|
+
const uniqueIds = [...new Set(citationIds)];
|
|
1329
|
+
const itemsMap = await this.manager.getByIds(uniqueIds);
|
|
1330
|
+
const missing = [];
|
|
1331
|
+
const foundItems = [];
|
|
1332
|
+
for (const id of uniqueIds) {
|
|
1333
|
+
const item = itemsMap.get(id);
|
|
1334
|
+
if (item) {
|
|
1335
|
+
foundItems.push(item);
|
|
1336
|
+
} else {
|
|
1337
|
+
missing.push(id);
|
|
1338
|
+
}
|
|
1284
1339
|
}
|
|
1285
|
-
|
|
1340
|
+
const sortedItems = this.sortItems(foundItems, sort);
|
|
1341
|
+
const entries = sortedItems.map((item) => formatFullEntry(item));
|
|
1342
|
+
return {
|
|
1343
|
+
entries,
|
|
1344
|
+
items: sortedItems,
|
|
1345
|
+
missing
|
|
1346
|
+
};
|
|
1286
1347
|
}
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1348
|
+
/**
|
|
1349
|
+
* Sort items according to the specified order
|
|
1350
|
+
*/
|
|
1351
|
+
sortItems(items, sort) {
|
|
1352
|
+
switch (sort) {
|
|
1353
|
+
case "citation-order":
|
|
1354
|
+
return items;
|
|
1355
|
+
case "author":
|
|
1356
|
+
return [...items].sort((a, b) => {
|
|
1357
|
+
const authorA = getFirstAuthorFamily(a);
|
|
1358
|
+
const authorB = getFirstAuthorFamily(b);
|
|
1359
|
+
return authorA.localeCompare(authorB);
|
|
1360
|
+
});
|
|
1361
|
+
case "year":
|
|
1362
|
+
return [...items].sort((a, b) => {
|
|
1363
|
+
const yearA = getYear(a);
|
|
1364
|
+
const yearB = getYear(b);
|
|
1365
|
+
return yearA - yearB;
|
|
1366
|
+
});
|
|
1367
|
+
default:
|
|
1368
|
+
return items;
|
|
1293
1369
|
}
|
|
1294
|
-
return null;
|
|
1295
1370
|
}
|
|
1296
1371
|
};
|
|
1297
1372
|
|
|
@@ -1330,6 +1405,7 @@ var Pipeline = class {
|
|
|
1330
1405
|
}
|
|
1331
1406
|
}
|
|
1332
1407
|
);
|
|
1408
|
+
this.bibliographyGenerator = new BibliographyGenerator(this.referenceManager);
|
|
1333
1409
|
this.transformer = new Transformer(
|
|
1334
1410
|
this.templateEngine,
|
|
1335
1411
|
this.templateLoader,
|
|
@@ -1346,6 +1422,7 @@ var Pipeline = class {
|
|
|
1346
1422
|
referenceManager;
|
|
1347
1423
|
citationExtractor;
|
|
1348
1424
|
citationFormatter;
|
|
1425
|
+
bibliographyGenerator;
|
|
1349
1426
|
transformer;
|
|
1350
1427
|
renderer;
|
|
1351
1428
|
warnings = [];
|
|
@@ -1355,9 +1432,10 @@ var Pipeline = class {
|
|
|
1355
1432
|
async run(inputPath, options) {
|
|
1356
1433
|
this.warnings = [];
|
|
1357
1434
|
try {
|
|
1358
|
-
|
|
1435
|
+
let presentation = await this.parseSource(inputPath);
|
|
1359
1436
|
const citationIds = this.collectCitations(presentation);
|
|
1360
1437
|
await this.resolveReferences(citationIds);
|
|
1438
|
+
presentation = await this.processBibliography(presentation, citationIds);
|
|
1361
1439
|
const transformedSlides = await this.transformSlides(presentation);
|
|
1362
1440
|
const output = this.render(transformedSlides, presentation);
|
|
1363
1441
|
if (options?.outputPath) {
|
|
@@ -1381,9 +1459,10 @@ var Pipeline = class {
|
|
|
1381
1459
|
async runWithResult(inputPath, options) {
|
|
1382
1460
|
this.warnings = [];
|
|
1383
1461
|
try {
|
|
1384
|
-
|
|
1462
|
+
let presentation = await this.parseSource(inputPath);
|
|
1385
1463
|
const citationIds = this.collectCitations(presentation);
|
|
1386
1464
|
await this.resolveReferences(citationIds);
|
|
1465
|
+
presentation = await this.processBibliography(presentation, citationIds);
|
|
1387
1466
|
const transformedSlides = await this.transformSlides(presentation);
|
|
1388
1467
|
const output = this.render(transformedSlides, presentation);
|
|
1389
1468
|
if (options?.outputPath) {
|
|
@@ -1459,6 +1538,13 @@ var Pipeline = class {
|
|
|
1459
1538
|
if (!this.config.references.enabled || ids.length === 0) {
|
|
1460
1539
|
return /* @__PURE__ */ new Map();
|
|
1461
1540
|
}
|
|
1541
|
+
const isAvailable = await this.referenceManager.isAvailable();
|
|
1542
|
+
if (!isAvailable) {
|
|
1543
|
+
this.warnings.push(
|
|
1544
|
+
"reference-manager CLI is not available. Install it to enable citation features: npm install -g @ncukondo/reference-manager"
|
|
1545
|
+
);
|
|
1546
|
+
return /* @__PURE__ */ new Map();
|
|
1547
|
+
}
|
|
1462
1548
|
try {
|
|
1463
1549
|
const items = await this.referenceManager.getByIds(ids);
|
|
1464
1550
|
for (const id of ids) {
|
|
@@ -1507,10 +1593,97 @@ var Pipeline = class {
|
|
|
1507
1593
|
);
|
|
1508
1594
|
}
|
|
1509
1595
|
}
|
|
1596
|
+
/**
|
|
1597
|
+
* Process bibliography slides with autoGenerate: true
|
|
1598
|
+
* Populates references array from collected citations
|
|
1599
|
+
*/
|
|
1600
|
+
async processBibliography(presentation, citationIds) {
|
|
1601
|
+
if (!this.config.references.enabled || citationIds.length === 0) {
|
|
1602
|
+
return presentation;
|
|
1603
|
+
}
|
|
1604
|
+
const hasBibliographyAutoGenerate = presentation.slides.some(
|
|
1605
|
+
(slide) => slide.template === "bibliography" && slide.content?.["autoGenerate"] === true
|
|
1606
|
+
);
|
|
1607
|
+
if (!hasBibliographyAutoGenerate) {
|
|
1608
|
+
return presentation;
|
|
1609
|
+
}
|
|
1610
|
+
const isAvailable = await this.referenceManager.isAvailable();
|
|
1611
|
+
if (!isAvailable) {
|
|
1612
|
+
return presentation;
|
|
1613
|
+
}
|
|
1614
|
+
try {
|
|
1615
|
+
const updatedSlides = await Promise.all(
|
|
1616
|
+
presentation.slides.map(async (slide) => {
|
|
1617
|
+
if (slide.template === "bibliography" && slide.content?.["autoGenerate"] === true) {
|
|
1618
|
+
const sort = slide.content["sort"] || "citation-order";
|
|
1619
|
+
const result = await this.bibliographyGenerator.generate(
|
|
1620
|
+
citationIds,
|
|
1621
|
+
{ sort }
|
|
1622
|
+
);
|
|
1623
|
+
for (const id of result.missing) {
|
|
1624
|
+
this.warnings.push(`Bibliography: reference not found: ${id}`);
|
|
1625
|
+
}
|
|
1626
|
+
const references = result.items.map((item) => ({
|
|
1627
|
+
id: item.id,
|
|
1628
|
+
authors: this.formatAuthorsForTemplate(item.author),
|
|
1629
|
+
title: item.title || "",
|
|
1630
|
+
year: this.getYear(item),
|
|
1631
|
+
journal: item["container-title"],
|
|
1632
|
+
volume: item.volume,
|
|
1633
|
+
pages: item.page,
|
|
1634
|
+
doi: item.DOI,
|
|
1635
|
+
url: item.URL
|
|
1636
|
+
}));
|
|
1637
|
+
return {
|
|
1638
|
+
...slide,
|
|
1639
|
+
content: {
|
|
1640
|
+
...slide.content,
|
|
1641
|
+
references,
|
|
1642
|
+
_autoGenerated: true,
|
|
1643
|
+
_generatedEntries: result.entries
|
|
1644
|
+
}
|
|
1645
|
+
};
|
|
1646
|
+
}
|
|
1647
|
+
return slide;
|
|
1648
|
+
})
|
|
1649
|
+
);
|
|
1650
|
+
return {
|
|
1651
|
+
...presentation,
|
|
1652
|
+
slides: updatedSlides
|
|
1653
|
+
};
|
|
1654
|
+
} catch (error) {
|
|
1655
|
+
this.warnings.push(
|
|
1656
|
+
`Failed to auto-generate bibliography: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
1657
|
+
);
|
|
1658
|
+
return presentation;
|
|
1659
|
+
}
|
|
1660
|
+
}
|
|
1661
|
+
/**
|
|
1662
|
+
* Format authors for template-compatible format
|
|
1663
|
+
*/
|
|
1664
|
+
formatAuthorsForTemplate(authors) {
|
|
1665
|
+
if (!authors || authors.length === 0) {
|
|
1666
|
+
return void 0;
|
|
1667
|
+
}
|
|
1668
|
+
return authors.map((a) => {
|
|
1669
|
+
const initial = a.given ? `${a.given.charAt(0)}.` : "";
|
|
1670
|
+
return initial ? `${a.family}, ${initial}` : a.family;
|
|
1671
|
+
});
|
|
1672
|
+
}
|
|
1673
|
+
/**
|
|
1674
|
+
* Get year from CSL item
|
|
1675
|
+
*/
|
|
1676
|
+
getYear(item) {
|
|
1677
|
+
const dateParts = item.issued?.["date-parts"];
|
|
1678
|
+
if (dateParts && dateParts[0] && dateParts[0][0]) {
|
|
1679
|
+
return dateParts[0][0];
|
|
1680
|
+
}
|
|
1681
|
+
return void 0;
|
|
1682
|
+
}
|
|
1510
1683
|
};
|
|
1511
1684
|
|
|
1512
1685
|
// src/index.ts
|
|
1513
|
-
var VERSION = "0.
|
|
1686
|
+
var VERSION = "0.4.0";
|
|
1514
1687
|
export {
|
|
1515
1688
|
ParseError,
|
|
1516
1689
|
Parser,
|