@ncukondo/reference-manager 0.5.3 → 0.7.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 +93 -0
- package/dist/chunks/action-menu-CTtINmWd.js +118 -0
- package/dist/chunks/action-menu-CTtINmWd.js.map +1 -0
- package/dist/chunks/{file-watcher-CBAbblss.js → file-watcher-D7oyc-9z.js} +55 -11
- package/dist/chunks/file-watcher-D7oyc-9z.js.map +1 -0
- package/dist/chunks/{index-Bl_mOQRe.js → index-_7NEUoS7.js} +271 -136
- package/dist/chunks/index-_7NEUoS7.js.map +1 -0
- package/dist/chunks/{loader-DuzyKV70.js → loader-BItrdVWG.js} +149 -26
- package/dist/chunks/loader-BItrdVWG.js.map +1 -0
- package/dist/chunks/search-prompt-D67WyKrY.js +179 -0
- package/dist/chunks/search-prompt-D67WyKrY.js.map +1 -0
- package/dist/chunks/tty-CDBIQraQ.js +17 -0
- package/dist/chunks/tty-CDBIQraQ.js.map +1 -0
- package/dist/cli/commands/list.d.ts +7 -1
- package/dist/cli/commands/list.d.ts.map +1 -1
- package/dist/cli/commands/search.d.ts +26 -1
- package/dist/cli/commands/search.d.ts.map +1 -1
- package/dist/cli/completion.d.ts +65 -0
- package/dist/cli/completion.d.ts.map +1 -0
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli.js +535 -119
- package/dist/cli.js.map +1 -1
- package/dist/config/defaults.d.ts.map +1 -1
- package/dist/config/loader.d.ts.map +1 -1
- package/dist/config/schema.d.ts +97 -0
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/features/import/importer.d.ts.map +1 -1
- package/dist/features/interactive/action-menu.d.ts +56 -0
- package/dist/features/interactive/action-menu.d.ts.map +1 -0
- package/dist/features/interactive/debounce.d.ts +22 -0
- package/dist/features/interactive/debounce.d.ts.map +1 -0
- package/dist/features/interactive/format.d.ts +52 -0
- package/dist/features/interactive/format.d.ts.map +1 -0
- package/dist/features/interactive/search-prompt.d.ts +47 -0
- package/dist/features/interactive/search-prompt.d.ts.map +1 -0
- package/dist/features/interactive/tty.d.ts +20 -0
- package/dist/features/interactive/tty.d.ts.map +1 -0
- package/dist/features/operations/add.d.ts.map +1 -1
- package/dist/features/operations/list.d.ts +12 -3
- package/dist/features/operations/list.d.ts.map +1 -1
- package/dist/features/operations/search.d.ts +19 -3
- package/dist/features/operations/search.d.ts.map +1 -1
- package/dist/features/pagination/aliases.d.ts +14 -0
- package/dist/features/pagination/aliases.d.ts.map +1 -0
- package/dist/features/pagination/index.d.ts +8 -0
- package/dist/features/pagination/index.d.ts.map +1 -0
- package/dist/features/pagination/paginate.d.ts +20 -0
- package/dist/features/pagination/paginate.d.ts.map +1 -0
- package/dist/features/pagination/sorter.d.ts +16 -0
- package/dist/features/pagination/sorter.d.ts.map +1 -0
- package/dist/features/pagination/types.d.ts +74 -0
- package/dist/features/pagination/types.d.ts.map +1 -0
- package/dist/index.js +13 -12
- package/dist/index.js.map +1 -1
- package/dist/mcp/context.d.ts +4 -4
- package/dist/mcp/context.d.ts.map +1 -1
- package/dist/mcp/resources/index.d.ts +3 -3
- package/dist/mcp/resources/index.d.ts.map +1 -1
- package/dist/mcp/resources/library.d.ts +5 -5
- package/dist/mcp/resources/library.d.ts.map +1 -1
- package/dist/mcp/tools/add.d.ts +3 -3
- package/dist/mcp/tools/add.d.ts.map +1 -1
- package/dist/mcp/tools/cite.d.ts +3 -3
- package/dist/mcp/tools/cite.d.ts.map +1 -1
- package/dist/mcp/tools/fulltext.d.ts +7 -7
- package/dist/mcp/tools/fulltext.d.ts.map +1 -1
- package/dist/mcp/tools/index.d.ts +3 -3
- package/dist/mcp/tools/index.d.ts.map +1 -1
- package/dist/mcp/tools/list.d.ts +10 -3
- package/dist/mcp/tools/list.d.ts.map +1 -1
- package/dist/mcp/tools/remove.d.ts +3 -3
- package/dist/mcp/tools/remove.d.ts.map +1 -1
- package/dist/mcp/tools/search.d.ts +10 -3
- package/dist/mcp/tools/search.d.ts.map +1 -1
- package/dist/server/routes/list.d.ts +13 -0
- package/dist/server/routes/list.d.ts.map +1 -1
- package/dist/server/routes/search.d.ts +14 -0
- package/dist/server/routes/search.d.ts.map +1 -1
- package/dist/server.js +4 -4
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/object.d.ts +16 -0
- package/dist/utils/object.d.ts.map +1 -0
- package/package.json +4 -1
- package/dist/chunks/file-watcher-CBAbblss.js.map +0 -1
- package/dist/chunks/index-Bl_mOQRe.js.map +0 -1
- package/dist/chunks/loader-DuzyKV70.js.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Hono } from "hono";
|
|
2
|
-
import { e as CslItemSchema, d as detectDuplicate, t as tokenize, s as search$1, b as sortResults, L as Library, F as FileWatcher } from "./file-watcher-
|
|
2
|
+
import { e as CslItemSchema, d as detectDuplicate, h as generateId, q as sortOrderSchema, u as sortFieldSchema, p as pickDefined, t as tokenize, s as search$1, b as sortResults, v as searchSortFieldSchema, L as Library, F as FileWatcher } from "./file-watcher-D7oyc-9z.js";
|
|
3
3
|
import { existsSync, readFileSync } from "node:fs";
|
|
4
4
|
import { Cite } from "@citation-js/core";
|
|
5
5
|
import "@citation-js/plugin-doi";
|
|
@@ -30,6 +30,92 @@ async function updateReference(library, options) {
|
|
|
30
30
|
}
|
|
31
31
|
return result;
|
|
32
32
|
}
|
|
33
|
+
function getCreatedAt(item) {
|
|
34
|
+
const createdAt = item.custom?.created_at;
|
|
35
|
+
if (!createdAt) return 0;
|
|
36
|
+
return new Date(createdAt).getTime();
|
|
37
|
+
}
|
|
38
|
+
function getUpdatedAt(item) {
|
|
39
|
+
const timestamp = item.custom?.timestamp;
|
|
40
|
+
if (timestamp) return new Date(timestamp).getTime();
|
|
41
|
+
return getCreatedAt(item);
|
|
42
|
+
}
|
|
43
|
+
function getPublishedDate(item) {
|
|
44
|
+
const dateParts = item.issued?.["date-parts"]?.[0];
|
|
45
|
+
if (!dateParts || dateParts.length === 0) return 0;
|
|
46
|
+
const year = dateParts[0] ?? 0;
|
|
47
|
+
const month = dateParts[1] ?? 1;
|
|
48
|
+
const day = dateParts[2] ?? 1;
|
|
49
|
+
return new Date(year, month - 1, day).getTime();
|
|
50
|
+
}
|
|
51
|
+
function getAuthorName(item) {
|
|
52
|
+
const firstAuthor = item.author?.[0];
|
|
53
|
+
if (!firstAuthor) return "Anonymous";
|
|
54
|
+
return firstAuthor.family ?? firstAuthor.literal ?? "Anonymous";
|
|
55
|
+
}
|
|
56
|
+
function getTitle(item) {
|
|
57
|
+
return item.title ?? "";
|
|
58
|
+
}
|
|
59
|
+
function getSortValue(item, field) {
|
|
60
|
+
switch (field) {
|
|
61
|
+
case "created":
|
|
62
|
+
return getCreatedAt(item);
|
|
63
|
+
case "updated":
|
|
64
|
+
return getUpdatedAt(item);
|
|
65
|
+
case "published":
|
|
66
|
+
return getPublishedDate(item);
|
|
67
|
+
case "author":
|
|
68
|
+
return getAuthorName(item).toLowerCase();
|
|
69
|
+
case "title":
|
|
70
|
+
return getTitle(item).toLowerCase();
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
function compareValues(a, b, order) {
|
|
74
|
+
const multiplier = order === "desc" ? -1 : 1;
|
|
75
|
+
if (typeof a === "number" && typeof b === "number") {
|
|
76
|
+
return (a - b) * multiplier;
|
|
77
|
+
}
|
|
78
|
+
const strA = String(a);
|
|
79
|
+
const strB = String(b);
|
|
80
|
+
return strA.localeCompare(strB) * multiplier;
|
|
81
|
+
}
|
|
82
|
+
function sortReferences(items, sort, order) {
|
|
83
|
+
return [...items].sort((a, b) => {
|
|
84
|
+
const aValue = getSortValue(a, sort);
|
|
85
|
+
const bValue = getSortValue(b, sort);
|
|
86
|
+
const primaryCompare = compareValues(aValue, bValue, order);
|
|
87
|
+
if (primaryCompare !== 0) return primaryCompare;
|
|
88
|
+
const aCreated = getCreatedAt(a);
|
|
89
|
+
const bCreated = getCreatedAt(b);
|
|
90
|
+
const createdCompare = bCreated - aCreated;
|
|
91
|
+
if (createdCompare !== 0) return createdCompare;
|
|
92
|
+
return a.id.localeCompare(b.id);
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
function paginate(items, options) {
|
|
96
|
+
const offset = options.offset ?? 0;
|
|
97
|
+
const limit = options.limit ?? 0;
|
|
98
|
+
if (limit < 0) {
|
|
99
|
+
throw new Error("limit must be non-negative");
|
|
100
|
+
}
|
|
101
|
+
if (offset < 0) {
|
|
102
|
+
throw new Error("offset must be non-negative");
|
|
103
|
+
}
|
|
104
|
+
const isUnlimited = limit === 0;
|
|
105
|
+
const afterOffset = items.slice(offset);
|
|
106
|
+
const paginatedItems = isUnlimited ? afterOffset : afterOffset.slice(0, limit);
|
|
107
|
+
let nextOffset = null;
|
|
108
|
+
if (!isUnlimited && paginatedItems.length > 0) {
|
|
109
|
+
const nextPosition = offset + paginatedItems.length;
|
|
110
|
+
if (nextPosition < items.length) {
|
|
111
|
+
nextOffset = nextPosition;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return {
|
|
115
|
+
items: paginatedItems,
|
|
116
|
+
nextOffset
|
|
117
|
+
};
|
|
118
|
+
}
|
|
33
119
|
const BUILTIN_STYLES = ["apa", "vancouver", "harvard"];
|
|
34
120
|
function isBuiltinStyle(styleName) {
|
|
35
121
|
return BUILTIN_STYLES.includes(styleName);
|
|
@@ -764,13 +850,14 @@ async function processIdentifiers(inputs, options) {
|
|
|
764
850
|
for (const input of inputs) {
|
|
765
851
|
const isValidPmid = isPmid(input);
|
|
766
852
|
const isValidDoi = isDoi(input);
|
|
767
|
-
|
|
853
|
+
const isValidIsbn = isIsbn(input);
|
|
854
|
+
if (isValidPmid || isValidDoi || isValidIsbn) {
|
|
768
855
|
validIdentifiers.push(input);
|
|
769
856
|
} else {
|
|
770
857
|
const hint = looksLikeFilePath(input) ? " Hint: If this is a file path, check that the file exists." : "";
|
|
771
858
|
results.push({
|
|
772
859
|
success: false,
|
|
773
|
-
error: `Cannot interpret '${input}' as identifier (not a valid PMID or
|
|
860
|
+
error: `Cannot interpret '${input}' as identifier (not a valid PMID, DOI, or ISBN).${hint}`,
|
|
774
861
|
source: input
|
|
775
862
|
});
|
|
776
863
|
}
|
|
@@ -889,7 +976,8 @@ async function processImportResult(result, existingItems, addedIds, force, libra
|
|
|
889
976
|
}
|
|
890
977
|
}
|
|
891
978
|
const allExistingIds = /* @__PURE__ */ new Set([...existingItems.map((i) => i.id), ...addedIds]);
|
|
892
|
-
const
|
|
979
|
+
const generatedId = generateId(item);
|
|
980
|
+
const { id, changed } = resolveIdCollision(generatedId, allExistingIds);
|
|
893
981
|
const finalItem = { ...item, id };
|
|
894
982
|
await library.add(finalItem);
|
|
895
983
|
addedIds.add(id);
|
|
@@ -899,7 +987,7 @@ async function processImportResult(result, existingItems, addedIds, force, libra
|
|
|
899
987
|
};
|
|
900
988
|
if (changed) {
|
|
901
989
|
addedItem.idChanged = true;
|
|
902
|
-
addedItem.originalId =
|
|
990
|
+
addedItem.originalId = generatedId;
|
|
903
991
|
}
|
|
904
992
|
return { type: "added", item: addedItem };
|
|
905
993
|
}
|
|
@@ -930,6 +1018,47 @@ const add = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty(
|
|
|
930
1018
|
__proto__: null,
|
|
931
1019
|
addReferences
|
|
932
1020
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
1021
|
+
function buildPubmedConfig(config) {
|
|
1022
|
+
const pubmedConfig = {};
|
|
1023
|
+
if (config.pubmed.email !== void 0) {
|
|
1024
|
+
pubmedConfig.email = config.pubmed.email;
|
|
1025
|
+
}
|
|
1026
|
+
if (config.pubmed.apiKey !== void 0) {
|
|
1027
|
+
pubmedConfig.apiKey = config.pubmed.apiKey;
|
|
1028
|
+
}
|
|
1029
|
+
return pubmedConfig;
|
|
1030
|
+
}
|
|
1031
|
+
function createAddRoute(library, config) {
|
|
1032
|
+
const route = new Hono();
|
|
1033
|
+
route.post("/", async (c) => {
|
|
1034
|
+
let body;
|
|
1035
|
+
try {
|
|
1036
|
+
body = await c.req.json();
|
|
1037
|
+
} catch {
|
|
1038
|
+
return c.json({ error: "Invalid JSON" }, 400);
|
|
1039
|
+
}
|
|
1040
|
+
if (!body || typeof body !== "object") {
|
|
1041
|
+
return c.json({ error: "Request body must be an object" }, 400);
|
|
1042
|
+
}
|
|
1043
|
+
const { inputs, options } = body;
|
|
1044
|
+
if (!inputs || !Array.isArray(inputs) || inputs.length === 0) {
|
|
1045
|
+
return c.json({ error: "inputs must be a non-empty array of strings" }, 400);
|
|
1046
|
+
}
|
|
1047
|
+
if (!inputs.every((input) => typeof input === "string")) {
|
|
1048
|
+
return c.json({ error: "All inputs must be strings" }, 400);
|
|
1049
|
+
}
|
|
1050
|
+
const addOptions = {
|
|
1051
|
+
force: options?.force ?? false,
|
|
1052
|
+
pubmedConfig: buildPubmedConfig(config)
|
|
1053
|
+
};
|
|
1054
|
+
if (options?.format) {
|
|
1055
|
+
addOptions.format = options.format;
|
|
1056
|
+
}
|
|
1057
|
+
const result = await addReferences(inputs, library, addOptions);
|
|
1058
|
+
return c.json(result);
|
|
1059
|
+
});
|
|
1060
|
+
return route;
|
|
1061
|
+
}
|
|
933
1062
|
function formatAuthor(author) {
|
|
934
1063
|
const family = author.family || "";
|
|
935
1064
|
const givenInitial = author.given ? `${author.given.charAt(0)}.` : "";
|
|
@@ -1281,113 +1410,6 @@ const cite = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty
|
|
|
1281
1410
|
__proto__: null,
|
|
1282
1411
|
citeReferences
|
|
1283
1412
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
1284
|
-
async function listReferences(library, options) {
|
|
1285
|
-
const format = options.format ?? "pretty";
|
|
1286
|
-
const items = await library.getAll();
|
|
1287
|
-
switch (format) {
|
|
1288
|
-
case "json":
|
|
1289
|
-
return { items: items.map((item) => JSON.stringify(item)) };
|
|
1290
|
-
case "bibtex":
|
|
1291
|
-
return { items: items.map((item) => formatBibtex([item])) };
|
|
1292
|
-
case "ids-only":
|
|
1293
|
-
return { items: items.map((item) => item.id) };
|
|
1294
|
-
case "uuid":
|
|
1295
|
-
return {
|
|
1296
|
-
items: items.filter(
|
|
1297
|
-
(item) => Boolean(item.custom?.uuid)
|
|
1298
|
-
).map((item) => item.custom.uuid)
|
|
1299
|
-
};
|
|
1300
|
-
default:
|
|
1301
|
-
return { items: items.map((item) => formatPretty([item])) };
|
|
1302
|
-
}
|
|
1303
|
-
}
|
|
1304
|
-
const list = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
1305
|
-
__proto__: null,
|
|
1306
|
-
listReferences
|
|
1307
|
-
}, Symbol.toStringTag, { value: "Module" }));
|
|
1308
|
-
async function removeReference(library, options) {
|
|
1309
|
-
const { identifier, idType = "id" } = options;
|
|
1310
|
-
const result = await library.remove(identifier, { idType });
|
|
1311
|
-
if (result.removed) {
|
|
1312
|
-
await library.save();
|
|
1313
|
-
}
|
|
1314
|
-
return result;
|
|
1315
|
-
}
|
|
1316
|
-
async function searchReferences(library, options) {
|
|
1317
|
-
const format = options.format ?? "pretty";
|
|
1318
|
-
const query = options.query;
|
|
1319
|
-
const allItems = await library.getAll();
|
|
1320
|
-
let matchedItems;
|
|
1321
|
-
if (!query.trim()) {
|
|
1322
|
-
matchedItems = allItems;
|
|
1323
|
-
} else {
|
|
1324
|
-
const tokens = tokenize(query).tokens;
|
|
1325
|
-
const results = search$1(allItems, tokens);
|
|
1326
|
-
const sorted = sortResults(results);
|
|
1327
|
-
matchedItems = sorted.map((result) => result.reference);
|
|
1328
|
-
}
|
|
1329
|
-
switch (format) {
|
|
1330
|
-
case "json":
|
|
1331
|
-
return { items: matchedItems.map((item) => JSON.stringify(item)) };
|
|
1332
|
-
case "bibtex":
|
|
1333
|
-
return { items: matchedItems.map((item) => formatBibtex([item])) };
|
|
1334
|
-
case "ids-only":
|
|
1335
|
-
return { items: matchedItems.map((item) => item.id) };
|
|
1336
|
-
case "uuid":
|
|
1337
|
-
return {
|
|
1338
|
-
items: matchedItems.filter(
|
|
1339
|
-
(item) => Boolean(item.custom?.uuid)
|
|
1340
|
-
).map((item) => item.custom.uuid)
|
|
1341
|
-
};
|
|
1342
|
-
default:
|
|
1343
|
-
return { items: matchedItems.map((item) => formatPretty([item])) };
|
|
1344
|
-
}
|
|
1345
|
-
}
|
|
1346
|
-
const search = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
1347
|
-
__proto__: null,
|
|
1348
|
-
searchReferences
|
|
1349
|
-
}, Symbol.toStringTag, { value: "Module" }));
|
|
1350
|
-
function buildPubmedConfig(config) {
|
|
1351
|
-
const pubmedConfig = {};
|
|
1352
|
-
if (config.pubmed.email !== void 0) {
|
|
1353
|
-
pubmedConfig.email = config.pubmed.email;
|
|
1354
|
-
}
|
|
1355
|
-
if (config.pubmed.apiKey !== void 0) {
|
|
1356
|
-
pubmedConfig.apiKey = config.pubmed.apiKey;
|
|
1357
|
-
}
|
|
1358
|
-
return pubmedConfig;
|
|
1359
|
-
}
|
|
1360
|
-
function createAddRoute(library, config) {
|
|
1361
|
-
const route = new Hono();
|
|
1362
|
-
route.post("/", async (c) => {
|
|
1363
|
-
let body;
|
|
1364
|
-
try {
|
|
1365
|
-
body = await c.req.json();
|
|
1366
|
-
} catch {
|
|
1367
|
-
return c.json({ error: "Invalid JSON" }, 400);
|
|
1368
|
-
}
|
|
1369
|
-
if (!body || typeof body !== "object") {
|
|
1370
|
-
return c.json({ error: "Request body must be an object" }, 400);
|
|
1371
|
-
}
|
|
1372
|
-
const { inputs, options } = body;
|
|
1373
|
-
if (!inputs || !Array.isArray(inputs) || inputs.length === 0) {
|
|
1374
|
-
return c.json({ error: "inputs must be a non-empty array of strings" }, 400);
|
|
1375
|
-
}
|
|
1376
|
-
if (!inputs.every((input) => typeof input === "string")) {
|
|
1377
|
-
return c.json({ error: "All inputs must be strings" }, 400);
|
|
1378
|
-
}
|
|
1379
|
-
const addOptions = {
|
|
1380
|
-
force: options?.force ?? false,
|
|
1381
|
-
pubmedConfig: buildPubmedConfig(config)
|
|
1382
|
-
};
|
|
1383
|
-
if (options?.format) {
|
|
1384
|
-
addOptions.format = options.format;
|
|
1385
|
-
}
|
|
1386
|
-
const result = await addReferences(inputs, library, addOptions);
|
|
1387
|
-
return c.json(result);
|
|
1388
|
-
});
|
|
1389
|
-
return route;
|
|
1390
|
-
}
|
|
1391
1413
|
const CiteRequestSchema = z.object({
|
|
1392
1414
|
identifiers: z.array(z.string()).min(1, "identifiers must be a non-empty array"),
|
|
1393
1415
|
idType: z.enum(["id", "uuid", "doi", "pmid", "isbn"]).optional(),
|
|
@@ -1431,8 +1453,51 @@ const healthRoute = new Hono();
|
|
|
1431
1453
|
healthRoute.get("/", (c) => {
|
|
1432
1454
|
return c.json({ status: "ok" });
|
|
1433
1455
|
});
|
|
1456
|
+
function formatItems$1(items, format) {
|
|
1457
|
+
switch (format) {
|
|
1458
|
+
case "json":
|
|
1459
|
+
return items.map((item) => JSON.stringify(item));
|
|
1460
|
+
case "bibtex":
|
|
1461
|
+
return items.map((item) => formatBibtex([item]));
|
|
1462
|
+
case "ids-only":
|
|
1463
|
+
return items.map((item) => item.id);
|
|
1464
|
+
case "uuid":
|
|
1465
|
+
return items.filter(
|
|
1466
|
+
(item) => Boolean(item.custom?.uuid)
|
|
1467
|
+
).map((item) => item.custom.uuid);
|
|
1468
|
+
default:
|
|
1469
|
+
return items.map((item) => formatPretty([item]));
|
|
1470
|
+
}
|
|
1471
|
+
}
|
|
1472
|
+
async function listReferences(library, options) {
|
|
1473
|
+
const format = options.format ?? "pretty";
|
|
1474
|
+
const sort = options.sort ?? "updated";
|
|
1475
|
+
const order = options.order ?? "desc";
|
|
1476
|
+
const limit = options.limit ?? 0;
|
|
1477
|
+
const offset = options.offset ?? 0;
|
|
1478
|
+
const allItems = await library.getAll();
|
|
1479
|
+
const total = allItems.length;
|
|
1480
|
+
const sorted = sortReferences(allItems, sort, order);
|
|
1481
|
+
const { items: paginatedItems, nextOffset } = paginate(sorted, { limit, offset });
|
|
1482
|
+
const formattedItems = formatItems$1(paginatedItems, format);
|
|
1483
|
+
return {
|
|
1484
|
+
items: formattedItems,
|
|
1485
|
+
total,
|
|
1486
|
+
limit,
|
|
1487
|
+
offset,
|
|
1488
|
+
nextOffset
|
|
1489
|
+
};
|
|
1490
|
+
}
|
|
1491
|
+
const list = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
1492
|
+
__proto__: null,
|
|
1493
|
+
listReferences
|
|
1494
|
+
}, Symbol.toStringTag, { value: "Module" }));
|
|
1434
1495
|
const listRequestBodySchema = z.object({
|
|
1435
|
-
format: z.enum(["pretty", "json", "bibtex", "ids-only", "uuid"]).optional()
|
|
1496
|
+
format: z.enum(["pretty", "json", "bibtex", "ids-only", "uuid"]).optional(),
|
|
1497
|
+
sort: sortFieldSchema.optional(),
|
|
1498
|
+
order: sortOrderSchema.optional(),
|
|
1499
|
+
limit: z.number().int().min(0).optional(),
|
|
1500
|
+
offset: z.number().int().min(0).optional()
|
|
1436
1501
|
});
|
|
1437
1502
|
function createListRoute(library) {
|
|
1438
1503
|
const route = new Hono();
|
|
@@ -1445,18 +1510,30 @@ function createListRoute(library) {
|
|
|
1445
1510
|
}
|
|
1446
1511
|
const parseResult = listRequestBodySchema.safeParse(body);
|
|
1447
1512
|
if (!parseResult.success) {
|
|
1448
|
-
|
|
1513
|
+
const errorMessage = parseResult.error.issues[0]?.message ?? "Invalid request body";
|
|
1514
|
+
return c.json({ error: errorMessage }, 400);
|
|
1449
1515
|
}
|
|
1450
1516
|
const requestBody = parseResult.data;
|
|
1451
|
-
const options =
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1517
|
+
const options = pickDefined(requestBody, [
|
|
1518
|
+
"format",
|
|
1519
|
+
"sort",
|
|
1520
|
+
"order",
|
|
1521
|
+
"limit",
|
|
1522
|
+
"offset"
|
|
1523
|
+
]);
|
|
1455
1524
|
const result = await listReferences(library, options);
|
|
1456
1525
|
return c.json(result);
|
|
1457
1526
|
});
|
|
1458
1527
|
return route;
|
|
1459
1528
|
}
|
|
1529
|
+
async function removeReference(library, options) {
|
|
1530
|
+
const { identifier, idType = "id" } = options;
|
|
1531
|
+
const result = await library.remove(identifier, { idType });
|
|
1532
|
+
if (result.removed) {
|
|
1533
|
+
await library.save();
|
|
1534
|
+
}
|
|
1535
|
+
return result;
|
|
1536
|
+
}
|
|
1460
1537
|
function createReferencesRoute(library) {
|
|
1461
1538
|
const route = new Hono();
|
|
1462
1539
|
route.get("/", async (c) => {
|
|
@@ -1570,9 +1647,71 @@ function createReferencesRoute(library) {
|
|
|
1570
1647
|
});
|
|
1571
1648
|
return route;
|
|
1572
1649
|
}
|
|
1650
|
+
function formatItems(items, format) {
|
|
1651
|
+
switch (format) {
|
|
1652
|
+
case "json":
|
|
1653
|
+
return items.map((item) => JSON.stringify(item));
|
|
1654
|
+
case "bibtex":
|
|
1655
|
+
return items.map((item) => formatBibtex([item]));
|
|
1656
|
+
case "ids-only":
|
|
1657
|
+
return items.map((item) => item.id);
|
|
1658
|
+
case "uuid":
|
|
1659
|
+
return items.filter(
|
|
1660
|
+
(item) => Boolean(item.custom?.uuid)
|
|
1661
|
+
).map((item) => item.custom.uuid);
|
|
1662
|
+
default:
|
|
1663
|
+
return items.map((item) => formatPretty([item]));
|
|
1664
|
+
}
|
|
1665
|
+
}
|
|
1666
|
+
async function searchReferences(library, options) {
|
|
1667
|
+
const format = options.format ?? "pretty";
|
|
1668
|
+
const query = options.query;
|
|
1669
|
+
const sort = options.sort ?? "updated";
|
|
1670
|
+
const order = options.order ?? "desc";
|
|
1671
|
+
const limit = options.limit ?? 0;
|
|
1672
|
+
const offset = options.offset ?? 0;
|
|
1673
|
+
const allItems = await library.getAll();
|
|
1674
|
+
let matchedItems;
|
|
1675
|
+
if (!query.trim()) {
|
|
1676
|
+
matchedItems = allItems;
|
|
1677
|
+
} else {
|
|
1678
|
+
const tokens = tokenize(query).tokens;
|
|
1679
|
+
const results = search$1(allItems, tokens);
|
|
1680
|
+
if (sort === "relevance") {
|
|
1681
|
+
const sorted2 = sortResults(results);
|
|
1682
|
+
matchedItems = order === "desc" ? sorted2.map((r) => r.reference) : sorted2.map((r) => r.reference).reverse();
|
|
1683
|
+
} else {
|
|
1684
|
+
matchedItems = results.map((r) => r.reference);
|
|
1685
|
+
}
|
|
1686
|
+
}
|
|
1687
|
+
const total = matchedItems.length;
|
|
1688
|
+
let sorted;
|
|
1689
|
+
if (sort === "relevance") {
|
|
1690
|
+
sorted = matchedItems;
|
|
1691
|
+
} else {
|
|
1692
|
+
sorted = sortReferences(matchedItems, sort, order);
|
|
1693
|
+
}
|
|
1694
|
+
const { items: paginatedItems, nextOffset } = paginate(sorted, { limit, offset });
|
|
1695
|
+
const formattedItems = formatItems(paginatedItems, format);
|
|
1696
|
+
return {
|
|
1697
|
+
items: formattedItems,
|
|
1698
|
+
total,
|
|
1699
|
+
limit,
|
|
1700
|
+
offset,
|
|
1701
|
+
nextOffset
|
|
1702
|
+
};
|
|
1703
|
+
}
|
|
1704
|
+
const search = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
1705
|
+
__proto__: null,
|
|
1706
|
+
searchReferences
|
|
1707
|
+
}, Symbol.toStringTag, { value: "Module" }));
|
|
1573
1708
|
const searchRequestBodySchema = z.object({
|
|
1574
1709
|
query: z.string(),
|
|
1575
|
-
format: z.enum(["pretty", "json", "bibtex", "ids-only", "uuid"]).optional()
|
|
1710
|
+
format: z.enum(["pretty", "json", "bibtex", "ids-only", "uuid"]).optional(),
|
|
1711
|
+
sort: searchSortFieldSchema.optional(),
|
|
1712
|
+
order: sortOrderSchema.optional(),
|
|
1713
|
+
limit: z.number().int().min(0).optional(),
|
|
1714
|
+
offset: z.number().int().min(0).optional()
|
|
1576
1715
|
});
|
|
1577
1716
|
function createSearchRoute(library) {
|
|
1578
1717
|
const route = new Hono();
|
|
@@ -1585,15 +1724,14 @@ function createSearchRoute(library) {
|
|
|
1585
1724
|
}
|
|
1586
1725
|
const parseResult = searchRequestBodySchema.safeParse(body);
|
|
1587
1726
|
if (!parseResult.success) {
|
|
1588
|
-
|
|
1727
|
+
const errorMessage = parseResult.error.issues[0]?.message ?? "Invalid request body";
|
|
1728
|
+
return c.json({ error: errorMessage }, 400);
|
|
1589
1729
|
}
|
|
1590
1730
|
const requestBody = parseResult.data;
|
|
1591
1731
|
const options = {
|
|
1592
|
-
query: requestBody.query
|
|
1732
|
+
query: requestBody.query,
|
|
1733
|
+
...pickDefined(requestBody, ["format", "sort", "order", "limit", "offset"])
|
|
1593
1734
|
};
|
|
1594
|
-
if (requestBody.format !== void 0) {
|
|
1595
|
-
options.format = requestBody.format;
|
|
1596
|
-
}
|
|
1597
1735
|
const result = await searchReferences(library, options);
|
|
1598
1736
|
return c.json(result);
|
|
1599
1737
|
});
|
|
@@ -1641,17 +1779,14 @@ async function startServerWithFileWatcher(libraryPath, config) {
|
|
|
1641
1779
|
}
|
|
1642
1780
|
export {
|
|
1643
1781
|
BUILTIN_STYLES as B,
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
list as
|
|
1651
|
-
|
|
1652
|
-
listReferences as l,
|
|
1653
|
-
removeReference as r,
|
|
1654
|
-
searchReferences as s,
|
|
1782
|
+
formatBibtex as a,
|
|
1783
|
+
add as b,
|
|
1784
|
+
createServer as c,
|
|
1785
|
+
cite as d,
|
|
1786
|
+
search as e,
|
|
1787
|
+
formatBibliographyCSL as f,
|
|
1788
|
+
list as l,
|
|
1789
|
+
startServerWithFileWatcher as s,
|
|
1655
1790
|
updateReference as u
|
|
1656
1791
|
};
|
|
1657
|
-
//# sourceMappingURL=index-
|
|
1792
|
+
//# sourceMappingURL=index-_7NEUoS7.js.map
|