@ncukondo/reference-manager 0.5.3 → 0.6.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 +57 -0
- package/dist/chunks/{file-watcher-CBAbblss.js → file-watcher-Cwfnnw92.js} +42 -10
- package/dist/chunks/file-watcher-Cwfnnw92.js.map +1 -0
- package/dist/chunks/{index-Bl_mOQRe.js → index-CQO8hLYm.js} +263 -132
- package/dist/chunks/index-CQO8hLYm.js.map +1 -0
- package/dist/chunks/{loader-DuzyKV70.js → loader-B_ZLxCQW.js} +97 -26
- package/dist/chunks/loader-B_ZLxCQW.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 +7 -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 +480 -118
- 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 +74 -0
- package/dist/config/schema.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 +3 -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, 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-Cwfnnw92.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);
|
|
@@ -930,6 +1016,47 @@ const add = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty(
|
|
|
930
1016
|
__proto__: null,
|
|
931
1017
|
addReferences
|
|
932
1018
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
1019
|
+
function buildPubmedConfig(config) {
|
|
1020
|
+
const pubmedConfig = {};
|
|
1021
|
+
if (config.pubmed.email !== void 0) {
|
|
1022
|
+
pubmedConfig.email = config.pubmed.email;
|
|
1023
|
+
}
|
|
1024
|
+
if (config.pubmed.apiKey !== void 0) {
|
|
1025
|
+
pubmedConfig.apiKey = config.pubmed.apiKey;
|
|
1026
|
+
}
|
|
1027
|
+
return pubmedConfig;
|
|
1028
|
+
}
|
|
1029
|
+
function createAddRoute(library, config) {
|
|
1030
|
+
const route = new Hono();
|
|
1031
|
+
route.post("/", async (c) => {
|
|
1032
|
+
let body;
|
|
1033
|
+
try {
|
|
1034
|
+
body = await c.req.json();
|
|
1035
|
+
} catch {
|
|
1036
|
+
return c.json({ error: "Invalid JSON" }, 400);
|
|
1037
|
+
}
|
|
1038
|
+
if (!body || typeof body !== "object") {
|
|
1039
|
+
return c.json({ error: "Request body must be an object" }, 400);
|
|
1040
|
+
}
|
|
1041
|
+
const { inputs, options } = body;
|
|
1042
|
+
if (!inputs || !Array.isArray(inputs) || inputs.length === 0) {
|
|
1043
|
+
return c.json({ error: "inputs must be a non-empty array of strings" }, 400);
|
|
1044
|
+
}
|
|
1045
|
+
if (!inputs.every((input) => typeof input === "string")) {
|
|
1046
|
+
return c.json({ error: "All inputs must be strings" }, 400);
|
|
1047
|
+
}
|
|
1048
|
+
const addOptions = {
|
|
1049
|
+
force: options?.force ?? false,
|
|
1050
|
+
pubmedConfig: buildPubmedConfig(config)
|
|
1051
|
+
};
|
|
1052
|
+
if (options?.format) {
|
|
1053
|
+
addOptions.format = options.format;
|
|
1054
|
+
}
|
|
1055
|
+
const result = await addReferences(inputs, library, addOptions);
|
|
1056
|
+
return c.json(result);
|
|
1057
|
+
});
|
|
1058
|
+
return route;
|
|
1059
|
+
}
|
|
933
1060
|
function formatAuthor(author) {
|
|
934
1061
|
const family = author.family || "";
|
|
935
1062
|
const givenInitial = author.given ? `${author.given.charAt(0)}.` : "";
|
|
@@ -1281,113 +1408,6 @@ const cite = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty
|
|
|
1281
1408
|
__proto__: null,
|
|
1282
1409
|
citeReferences
|
|
1283
1410
|
}, 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
1411
|
const CiteRequestSchema = z.object({
|
|
1392
1412
|
identifiers: z.array(z.string()).min(1, "identifiers must be a non-empty array"),
|
|
1393
1413
|
idType: z.enum(["id", "uuid", "doi", "pmid", "isbn"]).optional(),
|
|
@@ -1431,8 +1451,51 @@ const healthRoute = new Hono();
|
|
|
1431
1451
|
healthRoute.get("/", (c) => {
|
|
1432
1452
|
return c.json({ status: "ok" });
|
|
1433
1453
|
});
|
|
1454
|
+
function formatItems$1(items, format) {
|
|
1455
|
+
switch (format) {
|
|
1456
|
+
case "json":
|
|
1457
|
+
return items.map((item) => JSON.stringify(item));
|
|
1458
|
+
case "bibtex":
|
|
1459
|
+
return items.map((item) => formatBibtex([item]));
|
|
1460
|
+
case "ids-only":
|
|
1461
|
+
return items.map((item) => item.id);
|
|
1462
|
+
case "uuid":
|
|
1463
|
+
return items.filter(
|
|
1464
|
+
(item) => Boolean(item.custom?.uuid)
|
|
1465
|
+
).map((item) => item.custom.uuid);
|
|
1466
|
+
default:
|
|
1467
|
+
return items.map((item) => formatPretty([item]));
|
|
1468
|
+
}
|
|
1469
|
+
}
|
|
1470
|
+
async function listReferences(library, options) {
|
|
1471
|
+
const format = options.format ?? "pretty";
|
|
1472
|
+
const sort = options.sort ?? "updated";
|
|
1473
|
+
const order = options.order ?? "desc";
|
|
1474
|
+
const limit = options.limit ?? 0;
|
|
1475
|
+
const offset = options.offset ?? 0;
|
|
1476
|
+
const allItems = await library.getAll();
|
|
1477
|
+
const total = allItems.length;
|
|
1478
|
+
const sorted = sortReferences(allItems, sort, order);
|
|
1479
|
+
const { items: paginatedItems, nextOffset } = paginate(sorted, { limit, offset });
|
|
1480
|
+
const formattedItems = formatItems$1(paginatedItems, format);
|
|
1481
|
+
return {
|
|
1482
|
+
items: formattedItems,
|
|
1483
|
+
total,
|
|
1484
|
+
limit,
|
|
1485
|
+
offset,
|
|
1486
|
+
nextOffset
|
|
1487
|
+
};
|
|
1488
|
+
}
|
|
1489
|
+
const list = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
1490
|
+
__proto__: null,
|
|
1491
|
+
listReferences
|
|
1492
|
+
}, Symbol.toStringTag, { value: "Module" }));
|
|
1434
1493
|
const listRequestBodySchema = z.object({
|
|
1435
|
-
format: z.enum(["pretty", "json", "bibtex", "ids-only", "uuid"]).optional()
|
|
1494
|
+
format: z.enum(["pretty", "json", "bibtex", "ids-only", "uuid"]).optional(),
|
|
1495
|
+
sort: sortFieldSchema.optional(),
|
|
1496
|
+
order: sortOrderSchema.optional(),
|
|
1497
|
+
limit: z.number().int().min(0).optional(),
|
|
1498
|
+
offset: z.number().int().min(0).optional()
|
|
1436
1499
|
});
|
|
1437
1500
|
function createListRoute(library) {
|
|
1438
1501
|
const route = new Hono();
|
|
@@ -1445,18 +1508,30 @@ function createListRoute(library) {
|
|
|
1445
1508
|
}
|
|
1446
1509
|
const parseResult = listRequestBodySchema.safeParse(body);
|
|
1447
1510
|
if (!parseResult.success) {
|
|
1448
|
-
|
|
1511
|
+
const errorMessage = parseResult.error.issues[0]?.message ?? "Invalid request body";
|
|
1512
|
+
return c.json({ error: errorMessage }, 400);
|
|
1449
1513
|
}
|
|
1450
1514
|
const requestBody = parseResult.data;
|
|
1451
|
-
const options =
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1515
|
+
const options = pickDefined(requestBody, [
|
|
1516
|
+
"format",
|
|
1517
|
+
"sort",
|
|
1518
|
+
"order",
|
|
1519
|
+
"limit",
|
|
1520
|
+
"offset"
|
|
1521
|
+
]);
|
|
1455
1522
|
const result = await listReferences(library, options);
|
|
1456
1523
|
return c.json(result);
|
|
1457
1524
|
});
|
|
1458
1525
|
return route;
|
|
1459
1526
|
}
|
|
1527
|
+
async function removeReference(library, options) {
|
|
1528
|
+
const { identifier, idType = "id" } = options;
|
|
1529
|
+
const result = await library.remove(identifier, { idType });
|
|
1530
|
+
if (result.removed) {
|
|
1531
|
+
await library.save();
|
|
1532
|
+
}
|
|
1533
|
+
return result;
|
|
1534
|
+
}
|
|
1460
1535
|
function createReferencesRoute(library) {
|
|
1461
1536
|
const route = new Hono();
|
|
1462
1537
|
route.get("/", async (c) => {
|
|
@@ -1570,9 +1645,71 @@ function createReferencesRoute(library) {
|
|
|
1570
1645
|
});
|
|
1571
1646
|
return route;
|
|
1572
1647
|
}
|
|
1648
|
+
function formatItems(items, format) {
|
|
1649
|
+
switch (format) {
|
|
1650
|
+
case "json":
|
|
1651
|
+
return items.map((item) => JSON.stringify(item));
|
|
1652
|
+
case "bibtex":
|
|
1653
|
+
return items.map((item) => formatBibtex([item]));
|
|
1654
|
+
case "ids-only":
|
|
1655
|
+
return items.map((item) => item.id);
|
|
1656
|
+
case "uuid":
|
|
1657
|
+
return items.filter(
|
|
1658
|
+
(item) => Boolean(item.custom?.uuid)
|
|
1659
|
+
).map((item) => item.custom.uuid);
|
|
1660
|
+
default:
|
|
1661
|
+
return items.map((item) => formatPretty([item]));
|
|
1662
|
+
}
|
|
1663
|
+
}
|
|
1664
|
+
async function searchReferences(library, options) {
|
|
1665
|
+
const format = options.format ?? "pretty";
|
|
1666
|
+
const query = options.query;
|
|
1667
|
+
const sort = options.sort ?? "updated";
|
|
1668
|
+
const order = options.order ?? "desc";
|
|
1669
|
+
const limit = options.limit ?? 0;
|
|
1670
|
+
const offset = options.offset ?? 0;
|
|
1671
|
+
const allItems = await library.getAll();
|
|
1672
|
+
let matchedItems;
|
|
1673
|
+
if (!query.trim()) {
|
|
1674
|
+
matchedItems = allItems;
|
|
1675
|
+
} else {
|
|
1676
|
+
const tokens = tokenize(query).tokens;
|
|
1677
|
+
const results = search$1(allItems, tokens);
|
|
1678
|
+
if (sort === "relevance") {
|
|
1679
|
+
const sorted2 = sortResults(results);
|
|
1680
|
+
matchedItems = order === "desc" ? sorted2.map((r) => r.reference) : sorted2.map((r) => r.reference).reverse();
|
|
1681
|
+
} else {
|
|
1682
|
+
matchedItems = results.map((r) => r.reference);
|
|
1683
|
+
}
|
|
1684
|
+
}
|
|
1685
|
+
const total = matchedItems.length;
|
|
1686
|
+
let sorted;
|
|
1687
|
+
if (sort === "relevance") {
|
|
1688
|
+
sorted = matchedItems;
|
|
1689
|
+
} else {
|
|
1690
|
+
sorted = sortReferences(matchedItems, sort, order);
|
|
1691
|
+
}
|
|
1692
|
+
const { items: paginatedItems, nextOffset } = paginate(sorted, { limit, offset });
|
|
1693
|
+
const formattedItems = formatItems(paginatedItems, format);
|
|
1694
|
+
return {
|
|
1695
|
+
items: formattedItems,
|
|
1696
|
+
total,
|
|
1697
|
+
limit,
|
|
1698
|
+
offset,
|
|
1699
|
+
nextOffset
|
|
1700
|
+
};
|
|
1701
|
+
}
|
|
1702
|
+
const search = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
|
|
1703
|
+
__proto__: null,
|
|
1704
|
+
searchReferences
|
|
1705
|
+
}, Symbol.toStringTag, { value: "Module" }));
|
|
1573
1706
|
const searchRequestBodySchema = z.object({
|
|
1574
1707
|
query: z.string(),
|
|
1575
|
-
format: z.enum(["pretty", "json", "bibtex", "ids-only", "uuid"]).optional()
|
|
1708
|
+
format: z.enum(["pretty", "json", "bibtex", "ids-only", "uuid"]).optional(),
|
|
1709
|
+
sort: searchSortFieldSchema.optional(),
|
|
1710
|
+
order: sortOrderSchema.optional(),
|
|
1711
|
+
limit: z.number().int().min(0).optional(),
|
|
1712
|
+
offset: z.number().int().min(0).optional()
|
|
1576
1713
|
});
|
|
1577
1714
|
function createSearchRoute(library) {
|
|
1578
1715
|
const route = new Hono();
|
|
@@ -1585,15 +1722,14 @@ function createSearchRoute(library) {
|
|
|
1585
1722
|
}
|
|
1586
1723
|
const parseResult = searchRequestBodySchema.safeParse(body);
|
|
1587
1724
|
if (!parseResult.success) {
|
|
1588
|
-
|
|
1725
|
+
const errorMessage = parseResult.error.issues[0]?.message ?? "Invalid request body";
|
|
1726
|
+
return c.json({ error: errorMessage }, 400);
|
|
1589
1727
|
}
|
|
1590
1728
|
const requestBody = parseResult.data;
|
|
1591
1729
|
const options = {
|
|
1592
|
-
query: requestBody.query
|
|
1730
|
+
query: requestBody.query,
|
|
1731
|
+
...pickDefined(requestBody, ["format", "sort", "order", "limit", "offset"])
|
|
1593
1732
|
};
|
|
1594
|
-
if (requestBody.format !== void 0) {
|
|
1595
|
-
options.format = requestBody.format;
|
|
1596
|
-
}
|
|
1597
1733
|
const result = await searchReferences(library, options);
|
|
1598
1734
|
return c.json(result);
|
|
1599
1735
|
});
|
|
@@ -1641,17 +1777,12 @@ async function startServerWithFileWatcher(libraryPath, config) {
|
|
|
1641
1777
|
}
|
|
1642
1778
|
export {
|
|
1643
1779
|
BUILTIN_STYLES as B,
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
list as g,
|
|
1651
|
-
search as h,
|
|
1652
|
-
listReferences as l,
|
|
1653
|
-
removeReference as r,
|
|
1654
|
-
searchReferences as s,
|
|
1780
|
+
add as a,
|
|
1781
|
+
cite as b,
|
|
1782
|
+
createServer as c,
|
|
1783
|
+
search as d,
|
|
1784
|
+
list as l,
|
|
1785
|
+
startServerWithFileWatcher as s,
|
|
1655
1786
|
updateReference as u
|
|
1656
1787
|
};
|
|
1657
|
-
//# sourceMappingURL=index-
|
|
1788
|
+
//# sourceMappingURL=index-CQO8hLYm.js.map
|