@ncukondo/reference-manager 0.32.0 → 0.33.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/dist/chunks/{SearchableMultiSelect-jAKQd_B0.js → SearchableMultiSelect-B8QVnO_p.js} +2 -2
- package/dist/chunks/{SearchableMultiSelect-jAKQd_B0.js.map → SearchableMultiSelect-B8QVnO_p.js.map} +1 -1
- package/dist/chunks/{action-menu-DLEwSKrj.js → action-menu-i1v02Qig.js} +3 -3
- package/dist/chunks/{action-menu-DLEwSKrj.js.map → action-menu-i1v02Qig.js.map} +1 -1
- package/dist/chunks/{checker-kVM4S67y.js → checker-CnWQe7v2.js} +4 -4
- package/dist/chunks/{checker-kVM4S67y.js.map → checker-CnWQe7v2.js.map} +1 -1
- package/dist/chunks/{crossref-client-DcJ42Qt6.js → crossref-client-Dxwv2A5D.js} +2 -2
- package/dist/chunks/{crossref-client-DcJ42Qt6.js.map → crossref-client-Dxwv2A5D.js.map} +1 -1
- package/dist/chunks/{fix-interaction-DWUzp9Ri.js → fix-interaction-D_zhtL9k.js} +5 -5
- package/dist/chunks/{fix-interaction-DWUzp9Ri.js.map → fix-interaction-D_zhtL9k.js.map} +1 -1
- package/dist/chunks/{index-BuQm8A5F.js → index-DMShdNwY.js} +4 -4
- package/dist/chunks/{index-BuQm8A5F.js.map → index-DMShdNwY.js.map} +1 -1
- package/dist/chunks/{index-B8iEozpf.js → index-DpZ-Ma7M.js} +3 -3
- package/dist/chunks/index-DpZ-Ma7M.js.map +1 -0
- package/dist/chunks/{index-CmkN2-2A.js → index-PkCQJBdt.js} +75 -32
- package/dist/chunks/index-PkCQJBdt.js.map +1 -0
- package/dist/chunks/{index-B4-i4PrU.js → index-a52FHX03.js} +672 -16
- package/dist/chunks/index-a52FHX03.js.map +1 -0
- package/dist/chunks/{loader-BG2eomDC.js → loader-CMu82BI5.js} +42 -1
- package/dist/chunks/loader-CMu82BI5.js.map +1 -0
- package/dist/chunks/{pubmed-client-Bhzz4Gg5.js → pubmed-client-CPFYI4kR.js} +2 -2
- package/dist/chunks/{pubmed-client-Bhzz4Gg5.js.map → pubmed-client-CPFYI4kR.js.map} +1 -1
- package/dist/chunks/{reference-select-B9b9Ez7Q.js → reference-select-aEB3-5rp.js} +3 -3
- package/dist/chunks/{reference-select-B9b9Ez7Q.js.map → reference-select-aEB3-5rp.js.map} +1 -1
- package/dist/chunks/{style-select-aXByJLOo.js → style-select-CQ4BBBZJ.js} +3 -3
- package/dist/chunks/{style-select-aXByJLOo.js.map → style-select-CQ4BBBZJ.js.map} +1 -1
- package/dist/cli/commands/add.d.ts +9 -1
- package/dist/cli/commands/add.d.ts.map +1 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli.js +2 -2
- package/dist/config/defaults.d.ts.map +1 -1
- package/dist/config/key-parser.d.ts.map +1 -1
- package/dist/config/loader.d.ts.map +1 -1
- package/dist/config/schema.d.ts +42 -0
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/features/attachments/types.d.ts +5 -1
- package/dist/features/attachments/types.d.ts.map +1 -1
- package/dist/features/import/browser.d.ts +16 -0
- package/dist/features/import/browser.d.ts.map +1 -0
- package/dist/features/import/detector.d.ts +11 -2
- package/dist/features/import/detector.d.ts.map +1 -1
- package/dist/features/import/importer.d.ts +17 -0
- package/dist/features/import/importer.d.ts.map +1 -1
- package/dist/features/import/url-archive.d.ts +18 -0
- package/dist/features/import/url-archive.d.ts.map +1 -0
- package/dist/features/import/url-fetcher.d.ts +35 -0
- package/dist/features/import/url-fetcher.d.ts.map +1 -0
- package/dist/features/import/url-fulltext.d.ts +10 -0
- package/dist/features/import/url-fulltext.d.ts.map +1 -0
- package/dist/features/import/url-metadata.d.ts +34 -0
- package/dist/features/import/url-metadata.d.ts.map +1 -0
- package/dist/features/operations/add.d.ts +11 -0
- package/dist/features/operations/add.d.ts.map +1 -1
- package/dist/features/operations/json-output.d.ts +1 -0
- package/dist/features/operations/json-output.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/server.js +1 -1
- package/package.json +8 -1
- package/dist/chunks/index-B4-i4PrU.js.map +0 -1
- package/dist/chunks/index-B8iEozpf.js.map +0 -1
- package/dist/chunks/index-CmkN2-2A.js.map +0 -1
- package/dist/chunks/loader-BG2eomDC.js.map +0 -1
|
@@ -1,22 +1,26 @@
|
|
|
1
1
|
import { Hono } from "hono";
|
|
2
2
|
import { h as CslItemSchema, g as detectDuplicate, m as generateId, a as sortOrderSchema, b as sortFieldSchema, p as pickDefined, t as tokenize, s as search$1, f as sortResults, y as searchSortFieldSchema, L as Library, F as FileWatcher } from "./file-watcher-CWHg1yol.js";
|
|
3
3
|
import * as fs from "node:fs";
|
|
4
|
-
import { mkdtempSync, writeFileSync,
|
|
4
|
+
import { mkdtempSync, writeFileSync, readFileSync, existsSync } from "node:fs";
|
|
5
|
+
import fs__default, { stat, rename, copyFile, unlink, rm, readFile, mkdir, writeFile, access, mkdtemp, rmdir } from "node:fs/promises";
|
|
6
|
+
import { tmpdir } from "node:os";
|
|
7
|
+
import * as path from "node:path";
|
|
8
|
+
import path__default, { extname, join, dirname, basename } from "node:path";
|
|
5
9
|
import { Cite, plugins, util } from "@citation-js/core";
|
|
6
10
|
import "@citation-js/plugin-doi";
|
|
7
11
|
import "@citation-js/plugin-isbn";
|
|
8
12
|
import "@citation-js/plugin-bibtex";
|
|
9
13
|
import "@citation-js/plugin-ris";
|
|
14
|
+
import { createRequire } from "node:module";
|
|
15
|
+
import { chromium } from "playwright-core";
|
|
16
|
+
import TurndownService from "turndown";
|
|
17
|
+
import { gfm } from "turndown-plugin-gfm";
|
|
10
18
|
import { z } from "zod";
|
|
11
|
-
import * as path from "node:path";
|
|
12
|
-
import path__default, { extname, join, dirname, basename } from "node:path";
|
|
13
19
|
import "@citation-js/plugin-csl";
|
|
14
|
-
import fs__default, { stat, rename, copyFile, unlink, rm, readFile, mkdir, writeFile, access, mkdtemp, rmdir } from "node:fs/promises";
|
|
15
|
-
import { tmpdir } from "node:os";
|
|
16
20
|
import { exec, execFile } from "node:child_process";
|
|
17
21
|
import "node:crypto";
|
|
18
22
|
const name = "@ncukondo/reference-manager";
|
|
19
|
-
const version = "0.
|
|
23
|
+
const version = "0.33.0";
|
|
20
24
|
const description = "A local reference management tool using CSL-JSON as the single source of truth";
|
|
21
25
|
const publishConfig = { "access": "public" };
|
|
22
26
|
const type$1 = "module";
|
|
@@ -27,8 +31,8 @@ const types = "./dist/index.d.ts";
|
|
|
27
31
|
const exports$1 = { ".": { "import": "./dist/index.js", "types": "./dist/index.d.ts" } };
|
|
28
32
|
const files = ["dist", "bin"];
|
|
29
33
|
const scripts = { "dev": "vite", "build": "vite build && tsc --emitDeclarationOnly", "preview": "vite preview", "test": "vitest --project unit", "test:unit": "vitest --project unit", "test:e2e": "vitest run --project e2e", "test:remote": "vitest --project remote", "test:all": "vitest --project unit && vitest --project e2e && vitest --project remote", "test:watch": "vitest --watch --project unit", "test:coverage": "vitest run --coverage --project unit", "lint": "biome check .", "lint:fix": "biome check --write .", "format": "biome format --write .", "typecheck": "tsc --noEmit", "check:paths": "! grep -rn --include='*.ts' --exclude='*.test.ts' --exclude='*.d.ts' --exclude='path.ts' '\\.replace(/\\\\\\\\' src/ 2>/dev/null", "check:no-process-exit": "! grep -rn --include='*.ts' --exclude='*.test.ts' 'process\\.exit(' src/cli/ 2>/dev/null | grep -v 'helpers.ts' | grep -v '// '", "prepublishOnly": "npm run build", "prepare": "husky || true" };
|
|
30
|
-
const dependencies = { "@citation-js/core": "^0.7.16", "@citation-js/plugin-bibtex": "^0.7.21", "@citation-js/plugin-csl": "^0.7.16", "@citation-js/plugin-doi": "^0.7.21", "@citation-js/plugin-isbn": "^0.4.0", "@citation-js/plugin-ris": "^0.7.21", "@iarna/toml": "^2.2.5", "@modelcontextprotocol/sdk": "^1.25.1", "@ncukondo/academic-fulltext": "^0.2.6", "chokidar": "^5.0.0", "commander": "^12.1.0", "env-paths": "^3.0.0", "hono": "^4.11.1", "ink": "^6.6.0", "ink-ui": "^0.4.0", "js-yaml": "^4.1.1", "react": "^19.2.3", "tabtab": "^3.0.2", "write-file-atomic": "^7.0.0", "yaml": "^2.8.2", "zod": "^4.1.13" };
|
|
31
|
-
const devDependencies = { "@biomejs/biome": "^1.9.0", "@hono/node-server": "^1.19.7", "@types/chokidar": "^1.7.5", "@types/js-yaml": "^4.0.9", "@types/node": "^22.19.2", "@types/react": "^19.2.9", "@types/tabtab": "^3.0.4", "@types/write-file-atomic": "^4.0.3", "@vitest/coverage-v8": "^2.1.9", "husky": "^9.1.7", "lint-staged": "^16.2.7", "react-devtools-core": "^6.1.5", "typescript": "^5.6.0", "vite": "^6.0.0", "vite-node": "^2.1.0", "vitest": "^2.1.0" };
|
|
34
|
+
const dependencies = { "@citation-js/core": "^0.7.16", "@citation-js/plugin-bibtex": "^0.7.21", "@citation-js/plugin-csl": "^0.7.16", "@citation-js/plugin-doi": "^0.7.21", "@citation-js/plugin-isbn": "^0.4.0", "@citation-js/plugin-ris": "^0.7.21", "@iarna/toml": "^2.2.5", "@modelcontextprotocol/sdk": "^1.25.1", "@mozilla/readability": "^0.6.0", "@ncukondo/academic-fulltext": "^0.2.6", "chokidar": "^5.0.0", "commander": "^12.1.0", "env-paths": "^3.0.0", "hono": "^4.11.1", "ink": "^6.6.0", "ink-ui": "^0.4.0", "js-yaml": "^4.1.1", "playwright-core": "^1.58.2", "react": "^19.2.3", "tabtab": "^3.0.2", "turndown": "^7.2.2", "turndown-plugin-gfm": "^1.0.2", "write-file-atomic": "^7.0.0", "yaml": "^2.8.2", "zod": "^4.1.13" };
|
|
35
|
+
const devDependencies = { "@biomejs/biome": "^1.9.0", "@hono/node-server": "^1.19.7", "@types/chokidar": "^1.7.5", "@types/js-yaml": "^4.0.9", "@types/jsdom": "^28.0.1", "@types/node": "^22.19.2", "@types/react": "^19.2.9", "@types/tabtab": "^3.0.4", "@types/turndown": "^5.0.6", "@types/write-file-atomic": "^4.0.3", "@vitest/coverage-v8": "^2.1.9", "husky": "^9.1.7", "jsdom": "^29.0.1", "lint-staged": "^16.2.7", "react-devtools-core": "^6.1.5", "typescript": "^5.6.0", "vite": "^6.0.0", "vite-node": "^2.1.0", "vitest": "^2.1.0" };
|
|
32
36
|
const keywords = ["reference-manager", "csl-json", "bibliography", "pandoc", "citation"];
|
|
33
37
|
const author = "";
|
|
34
38
|
const license = "MIT";
|
|
@@ -92,7 +96,7 @@ function parseFilename(filename) {
|
|
|
92
96
|
ext: extWithoutDot
|
|
93
97
|
};
|
|
94
98
|
}
|
|
95
|
-
const RESERVED_ROLES = ["fulltext", "supplement", "notes", "draft"];
|
|
99
|
+
const RESERVED_ROLES = ["fulltext", "supplement", "notes", "draft", "archive"];
|
|
96
100
|
function isReservedRole(role) {
|
|
97
101
|
return RESERVED_ROLES.includes(role);
|
|
98
102
|
}
|
|
@@ -7394,7 +7398,7 @@ function extractRefText(item) {
|
|
|
7394
7398
|
}
|
|
7395
7399
|
return text2;
|
|
7396
7400
|
}
|
|
7397
|
-
function extractDoi(item) {
|
|
7401
|
+
function extractDoi$1(item) {
|
|
7398
7402
|
for (const link of qa(item, "a")) {
|
|
7399
7403
|
const href = link.getAttribute("href") ?? "";
|
|
7400
7404
|
const doiMatch = href.match(/doi\.org\/(.+)/);
|
|
@@ -7408,7 +7412,7 @@ function parseReferences(root) {
|
|
|
7408
7412
|
for (const item of qa(root, ".ltx_bibitem")) {
|
|
7409
7413
|
const id = item.getAttribute("id") ?? `ref${refs.length + 1}`;
|
|
7410
7414
|
const text2 = extractRefText(item);
|
|
7411
|
-
const doi = extractDoi(item);
|
|
7415
|
+
const doi = extractDoi$1(item);
|
|
7412
7416
|
const ref = { id, text: text2 };
|
|
7413
7417
|
if (doi)
|
|
7414
7418
|
ref.doi = doi;
|
|
@@ -11644,11 +11648,54 @@ function detectSingleIdentifier(input) {
|
|
|
11644
11648
|
if (isIsbn(input)) {
|
|
11645
11649
|
return "isbn";
|
|
11646
11650
|
}
|
|
11651
|
+
if (extractPubmedId(input) !== null) {
|
|
11652
|
+
return "pmid";
|
|
11653
|
+
}
|
|
11647
11654
|
if (isPmid(input)) {
|
|
11648
11655
|
return "pmid";
|
|
11649
11656
|
}
|
|
11657
|
+
if (isUrl(input)) {
|
|
11658
|
+
return "url";
|
|
11659
|
+
}
|
|
11650
11660
|
return "unknown";
|
|
11651
11661
|
}
|
|
11662
|
+
const PUBMED_URL_PATTERNS = [
|
|
11663
|
+
// https://pubmed.ncbi.nlm.nih.gov/{PMID}/
|
|
11664
|
+
{
|
|
11665
|
+
pattern: /^https?:\/\/pubmed\.ncbi\.nlm\.nih\.gov\/(\d+)\/?$/,
|
|
11666
|
+
extract: (m) => m[1]
|
|
11667
|
+
},
|
|
11668
|
+
// https://www.ncbi.nlm.nih.gov/pubmed/{PMID}
|
|
11669
|
+
{
|
|
11670
|
+
pattern: /^https?:\/\/(?:www\.)?ncbi\.nlm\.nih\.gov\/pubmed\/(\d+)\/?$/,
|
|
11671
|
+
extract: (m) => m[1]
|
|
11672
|
+
},
|
|
11673
|
+
// https://pmc.ncbi.nlm.nih.gov/articles/PMC{ID}/
|
|
11674
|
+
{
|
|
11675
|
+
pattern: /^https?:\/\/(?:www\.)?pmc\.ncbi\.nlm\.nih\.gov\/articles\/PMC(\d+)\/?$/,
|
|
11676
|
+
extract: (m) => `PMC${m[1]}`
|
|
11677
|
+
}
|
|
11678
|
+
];
|
|
11679
|
+
function extractPubmedId(input) {
|
|
11680
|
+
for (const { pattern, extract } of PUBMED_URL_PATTERNS) {
|
|
11681
|
+
const match = pattern.exec(input);
|
|
11682
|
+
if (match) {
|
|
11683
|
+
return extract(match);
|
|
11684
|
+
}
|
|
11685
|
+
}
|
|
11686
|
+
return null;
|
|
11687
|
+
}
|
|
11688
|
+
function isUrl(input) {
|
|
11689
|
+
if (!input) return false;
|
|
11690
|
+
const lower = input.toLowerCase();
|
|
11691
|
+
if (!lower.startsWith("http://") && !lower.startsWith("https://")) {
|
|
11692
|
+
return false;
|
|
11693
|
+
}
|
|
11694
|
+
if (isDoi(input)) return false;
|
|
11695
|
+
if (isArxiv(input)) return false;
|
|
11696
|
+
if (extractPubmedId(input) !== null) return false;
|
|
11697
|
+
return true;
|
|
11698
|
+
}
|
|
11652
11699
|
function isDoi(input) {
|
|
11653
11700
|
for (const prefix of DOI_URL_PREFIXES) {
|
|
11654
11701
|
if (input.toLowerCase().startsWith(prefix.toLowerCase())) {
|
|
@@ -12306,6 +12353,439 @@ function isEmptyFormat(content, format) {
|
|
|
12306
12353
|
}
|
|
12307
12354
|
return false;
|
|
12308
12355
|
}
|
|
12356
|
+
class BrowserNotFoundError extends Error {
|
|
12357
|
+
constructor(cause) {
|
|
12358
|
+
const message = [
|
|
12359
|
+
"Browser not found. URL import requires Chrome or Chromium.",
|
|
12360
|
+
"",
|
|
12361
|
+
" Install one of the following:",
|
|
12362
|
+
"",
|
|
12363
|
+
" Google Chrome: https://www.google.com/chrome/",
|
|
12364
|
+
" Chromium: sudo apt install chromium-browser (Ubuntu/Debian)",
|
|
12365
|
+
" brew install --cask chromium (macOS)",
|
|
12366
|
+
"",
|
|
12367
|
+
" Or specify the path manually:",
|
|
12368
|
+
"",
|
|
12369
|
+
" [url]",
|
|
12370
|
+
' browser_path = "/path/to/chrome"'
|
|
12371
|
+
].join("\n");
|
|
12372
|
+
super(message, { cause });
|
|
12373
|
+
this.name = "BrowserNotFoundError";
|
|
12374
|
+
}
|
|
12375
|
+
}
|
|
12376
|
+
async function launchBrowser(config) {
|
|
12377
|
+
try {
|
|
12378
|
+
const launchOptions = {
|
|
12379
|
+
headless: true
|
|
12380
|
+
};
|
|
12381
|
+
if (config.browserPath) {
|
|
12382
|
+
launchOptions.executablePath = config.browserPath;
|
|
12383
|
+
} else {
|
|
12384
|
+
launchOptions.channel = "chrome";
|
|
12385
|
+
}
|
|
12386
|
+
return await chromium.launch(launchOptions);
|
|
12387
|
+
} catch (error) {
|
|
12388
|
+
throw new BrowserNotFoundError(error instanceof Error ? error : void 0);
|
|
12389
|
+
}
|
|
12390
|
+
}
|
|
12391
|
+
async function captureMhtml(page) {
|
|
12392
|
+
const cdp = await page.context().newCDPSession(page);
|
|
12393
|
+
try {
|
|
12394
|
+
const { data } = await cdp.send("Page.captureSnapshot", { format: "mhtml" });
|
|
12395
|
+
return data;
|
|
12396
|
+
} finally {
|
|
12397
|
+
await cdp.detach();
|
|
12398
|
+
}
|
|
12399
|
+
}
|
|
12400
|
+
async function captureHtml(page) {
|
|
12401
|
+
return page.evaluate("document.documentElement.outerHTML");
|
|
12402
|
+
}
|
|
12403
|
+
async function createArchive(page, format) {
|
|
12404
|
+
if (format === "mhtml") {
|
|
12405
|
+
const data2 = await captureMhtml(page);
|
|
12406
|
+
return { data: data2, extension: "mhtml" };
|
|
12407
|
+
}
|
|
12408
|
+
const data = await captureHtml(page);
|
|
12409
|
+
return { data, extension: "html" };
|
|
12410
|
+
}
|
|
12411
|
+
async function extractContent(page) {
|
|
12412
|
+
return page.evaluate(`
|
|
12413
|
+
(() => {
|
|
12414
|
+
let content = null;
|
|
12415
|
+
try {
|
|
12416
|
+
if (typeof Readability !== "undefined") {
|
|
12417
|
+
const reader = new Readability(document.cloneNode(true));
|
|
12418
|
+
const article = reader.parse();
|
|
12419
|
+
content = article ? article.content : null;
|
|
12420
|
+
}
|
|
12421
|
+
} catch (e) {}
|
|
12422
|
+
return {
|
|
12423
|
+
content: content,
|
|
12424
|
+
fullHtml: document.documentElement.outerHTML,
|
|
12425
|
+
};
|
|
12426
|
+
})()
|
|
12427
|
+
`);
|
|
12428
|
+
}
|
|
12429
|
+
function htmlToMarkdown(html2) {
|
|
12430
|
+
const turndown = new TurndownService({
|
|
12431
|
+
headingStyle: "atx",
|
|
12432
|
+
codeBlockStyle: "fenced"
|
|
12433
|
+
});
|
|
12434
|
+
turndown.use(gfm);
|
|
12435
|
+
return turndown.turndown(html2);
|
|
12436
|
+
}
|
|
12437
|
+
async function generateFulltext(page) {
|
|
12438
|
+
const extracted = await extractContent(page);
|
|
12439
|
+
const html2 = extracted.content ?? extracted.fullHtml;
|
|
12440
|
+
if (!html2) {
|
|
12441
|
+
return "";
|
|
12442
|
+
}
|
|
12443
|
+
return htmlToMarkdown(html2);
|
|
12444
|
+
}
|
|
12445
|
+
const SCHEMA_TYPE_TO_CSL = {
|
|
12446
|
+
Legislation: "legislation",
|
|
12447
|
+
LegislationObject: "legislation",
|
|
12448
|
+
Report: "report",
|
|
12449
|
+
Article: "article",
|
|
12450
|
+
ScholarlyArticle: "article-journal",
|
|
12451
|
+
NewsArticle: "article-newspaper",
|
|
12452
|
+
WebPage: "webpage"
|
|
12453
|
+
};
|
|
12454
|
+
function parseDate(raw) {
|
|
12455
|
+
const cleaned = raw.replace(/\//g, "-");
|
|
12456
|
+
const parts = cleaned.split("-").map(Number);
|
|
12457
|
+
if (parts.length >= 1 && !Number.isNaN(parts[0])) {
|
|
12458
|
+
return { "date-parts": [parts.filter((p) => !Number.isNaN(p))] };
|
|
12459
|
+
}
|
|
12460
|
+
return void 0;
|
|
12461
|
+
}
|
|
12462
|
+
function isEmptyAuthor(a) {
|
|
12463
|
+
return !a.family && !a.given && !a.literal;
|
|
12464
|
+
}
|
|
12465
|
+
function parseName(name2) {
|
|
12466
|
+
const trimmed = name2.trim();
|
|
12467
|
+
if (!trimmed) return { literal: "" };
|
|
12468
|
+
if (trimmed.includes(",")) {
|
|
12469
|
+
const parts = trimmed.split(",");
|
|
12470
|
+
const family = parts[0] ?? "";
|
|
12471
|
+
const given = parts.slice(1).join(",").trim();
|
|
12472
|
+
const result = { family: family.trim() };
|
|
12473
|
+
if (given) result.given = given;
|
|
12474
|
+
return result;
|
|
12475
|
+
}
|
|
12476
|
+
const spaceIdx = trimmed.lastIndexOf(" ");
|
|
12477
|
+
if (spaceIdx > 0) {
|
|
12478
|
+
return {
|
|
12479
|
+
given: trimmed.slice(0, spaceIdx),
|
|
12480
|
+
family: trimmed.slice(spaceIdx + 1)
|
|
12481
|
+
};
|
|
12482
|
+
}
|
|
12483
|
+
return { literal: trimmed };
|
|
12484
|
+
}
|
|
12485
|
+
const PRIORITY_SCHEMA_TYPES = /* @__PURE__ */ new Set([
|
|
12486
|
+
"Article",
|
|
12487
|
+
"ScholarlyArticle",
|
|
12488
|
+
"NewsArticle",
|
|
12489
|
+
"Report",
|
|
12490
|
+
"Legislation",
|
|
12491
|
+
"LegislationObject"
|
|
12492
|
+
]);
|
|
12493
|
+
function isObj(v) {
|
|
12494
|
+
return v != null && typeof v === "object" && !Array.isArray(v);
|
|
12495
|
+
}
|
|
12496
|
+
function findInGraph(graph) {
|
|
12497
|
+
for (const item of graph) {
|
|
12498
|
+
if (!isObj(item)) continue;
|
|
12499
|
+
const t = item["@type"];
|
|
12500
|
+
if (typeof t === "string" && PRIORITY_SCHEMA_TYPES.has(t)) return item;
|
|
12501
|
+
}
|
|
12502
|
+
for (const item of graph) {
|
|
12503
|
+
if (isObj(item) && item.name) return item;
|
|
12504
|
+
}
|
|
12505
|
+
return void 0;
|
|
12506
|
+
}
|
|
12507
|
+
function findBestJsonLdItem(jsonLdArray) {
|
|
12508
|
+
for (const entry of jsonLdArray) {
|
|
12509
|
+
if (!isObj(entry)) continue;
|
|
12510
|
+
if (Array.isArray(entry["@graph"])) {
|
|
12511
|
+
const found = findInGraph(entry["@graph"]);
|
|
12512
|
+
if (found) return found;
|
|
12513
|
+
}
|
|
12514
|
+
if (entry["@type"]) return entry;
|
|
12515
|
+
}
|
|
12516
|
+
return void 0;
|
|
12517
|
+
}
|
|
12518
|
+
function extractJsonLdAuthor(rawAuthor) {
|
|
12519
|
+
const authors = Array.isArray(rawAuthor) ? rawAuthor : [rawAuthor];
|
|
12520
|
+
return authors.filter(isObj).map((a) => {
|
|
12521
|
+
const name2 = typeof a.name === "string" ? a.name : "";
|
|
12522
|
+
if (a["@type"] === "Organization") return { literal: name2 };
|
|
12523
|
+
return parseName(name2);
|
|
12524
|
+
});
|
|
12525
|
+
}
|
|
12526
|
+
function extractJsonLdPublisher(pub) {
|
|
12527
|
+
if (typeof pub === "string") return pub;
|
|
12528
|
+
if (isObj(pub) && typeof pub.name === "string") return pub.name;
|
|
12529
|
+
return void 0;
|
|
12530
|
+
}
|
|
12531
|
+
function extractJsonLdDate(item) {
|
|
12532
|
+
if (typeof item.datePublished === "string") return item.datePublished;
|
|
12533
|
+
if (typeof item.legislationDate === "string") return item.legislationDate;
|
|
12534
|
+
return void 0;
|
|
12535
|
+
}
|
|
12536
|
+
function extractDoi(value) {
|
|
12537
|
+
if (typeof value !== "string") return void 0;
|
|
12538
|
+
const normalized = value.replace(/^https?:\/\/(dx\.)?doi\.org\//, "");
|
|
12539
|
+
if (normalized.startsWith("10.")) return normalized;
|
|
12540
|
+
return void 0;
|
|
12541
|
+
}
|
|
12542
|
+
function setDateField(fields, dateStr) {
|
|
12543
|
+
if (!dateStr) return;
|
|
12544
|
+
const parsed = parseDate(dateStr);
|
|
12545
|
+
if (parsed) fields.issued = parsed;
|
|
12546
|
+
}
|
|
12547
|
+
function extractFromJsonLd(jsonLdArray) {
|
|
12548
|
+
const item = findBestJsonLdItem(jsonLdArray);
|
|
12549
|
+
if (!item) return {};
|
|
12550
|
+
const fields = {};
|
|
12551
|
+
if (typeof item.name === "string" && item.name) fields.title = item.name;
|
|
12552
|
+
if (typeof item["@type"] === "string") {
|
|
12553
|
+
const mapped = SCHEMA_TYPE_TO_CSL[item["@type"]];
|
|
12554
|
+
if (mapped) fields.type = mapped;
|
|
12555
|
+
}
|
|
12556
|
+
if (item.author) {
|
|
12557
|
+
const authors = extractJsonLdAuthor(item.author);
|
|
12558
|
+
if (authors.length) fields.author = authors;
|
|
12559
|
+
}
|
|
12560
|
+
setDateField(fields, extractJsonLdDate(item));
|
|
12561
|
+
const doi = extractDoi(item.identifier);
|
|
12562
|
+
if (doi) fields.DOI = doi;
|
|
12563
|
+
const pub = extractJsonLdPublisher(item.publisher);
|
|
12564
|
+
if (pub) fields.publisher = pub;
|
|
12565
|
+
if (typeof item.description === "string" && item.description) fields.abstract = item.description;
|
|
12566
|
+
return fields;
|
|
12567
|
+
}
|
|
12568
|
+
function extractFromCitation(citation) {
|
|
12569
|
+
const fields = {};
|
|
12570
|
+
if (typeof citation.citation_title === "string" && citation.citation_title) {
|
|
12571
|
+
fields.title = citation.citation_title;
|
|
12572
|
+
}
|
|
12573
|
+
const rawAuthors = citation.citation_author;
|
|
12574
|
+
if (rawAuthors) {
|
|
12575
|
+
const authorList = Array.isArray(rawAuthors) ? rawAuthors : [rawAuthors];
|
|
12576
|
+
const parsed = authorList.map((a) => parseName(a)).filter((a) => !isEmptyAuthor(a));
|
|
12577
|
+
if (parsed.length) fields.author = parsed;
|
|
12578
|
+
}
|
|
12579
|
+
const dateStr = (typeof citation.citation_date === "string" ? citation.citation_date : void 0) || (typeof citation.citation_publication_date === "string" ? citation.citation_publication_date : void 0);
|
|
12580
|
+
setDateField(fields, dateStr);
|
|
12581
|
+
if (typeof citation.citation_doi === "string" && citation.citation_doi) {
|
|
12582
|
+
fields.DOI = citation.citation_doi;
|
|
12583
|
+
}
|
|
12584
|
+
if (typeof citation.citation_journal_title === "string" && citation.citation_journal_title) {
|
|
12585
|
+
fields["container-title"] = citation.citation_journal_title;
|
|
12586
|
+
}
|
|
12587
|
+
return fields;
|
|
12588
|
+
}
|
|
12589
|
+
function dcString(val) {
|
|
12590
|
+
if (typeof val === "string") return val;
|
|
12591
|
+
if (Array.isArray(val) && val.length > 0) return val[0];
|
|
12592
|
+
return void 0;
|
|
12593
|
+
}
|
|
12594
|
+
function extractFromDublinCore(dc) {
|
|
12595
|
+
const fields = {};
|
|
12596
|
+
const title = dcString(dc["DC.title"]);
|
|
12597
|
+
if (title) fields.title = title;
|
|
12598
|
+
const rawCreator = dc["DC.creator"];
|
|
12599
|
+
if (rawCreator) {
|
|
12600
|
+
const creators = Array.isArray(rawCreator) ? rawCreator : [rawCreator];
|
|
12601
|
+
const parsed = creators.map((c) => parseName(c)).filter((a) => !isEmptyAuthor(a));
|
|
12602
|
+
if (parsed.length) fields.author = parsed;
|
|
12603
|
+
}
|
|
12604
|
+
setDateField(fields, dcString(dc["DC.date"]));
|
|
12605
|
+
const publisher = dcString(dc["DC.publisher"]);
|
|
12606
|
+
if (publisher) fields.publisher = publisher;
|
|
12607
|
+
const description2 = dcString(dc["DC.description"]);
|
|
12608
|
+
if (description2) fields.abstract = description2;
|
|
12609
|
+
const doi = extractDoi(dcString(dc["DC.identifier"]));
|
|
12610
|
+
if (doi) fields.DOI = doi;
|
|
12611
|
+
return fields;
|
|
12612
|
+
}
|
|
12613
|
+
function extractFromOpenGraph(og) {
|
|
12614
|
+
const fields = {};
|
|
12615
|
+
if (og["og:title"]) fields.title = og["og:title"];
|
|
12616
|
+
if (og["og:description"]) fields.abstract = og["og:description"];
|
|
12617
|
+
return fields;
|
|
12618
|
+
}
|
|
12619
|
+
const SIMPLE_KEYS = ["title", "type", "DOI", "container-title", "publisher", "abstract"];
|
|
12620
|
+
function mergeFields(...sources) {
|
|
12621
|
+
const merged = {};
|
|
12622
|
+
for (const key of SIMPLE_KEYS) {
|
|
12623
|
+
const source = sources.find((s) => s[key]);
|
|
12624
|
+
if (source?.[key]) merged[key] = source[key];
|
|
12625
|
+
}
|
|
12626
|
+
const authorSource = sources.find((s) => s.author?.length);
|
|
12627
|
+
if (authorSource?.author) merged.author = authorSource.author;
|
|
12628
|
+
const issuedSource = sources.find((s) => s.issued);
|
|
12629
|
+
if (issuedSource?.issued) merged.issued = issuedSource.issued;
|
|
12630
|
+
return merged;
|
|
12631
|
+
}
|
|
12632
|
+
async function extractMetadata(page) {
|
|
12633
|
+
const rawMeta = await page.evaluate(`
|
|
12634
|
+
(() => {
|
|
12635
|
+
const jsonLd = [...document.querySelectorAll('script[type="application/ld+json"]')]
|
|
12636
|
+
.map(el => { try { return JSON.parse(el.textContent || ""); } catch { return null; } })
|
|
12637
|
+
.filter(Boolean);
|
|
12638
|
+
|
|
12639
|
+
const citationMulti = {};
|
|
12640
|
+
for (const el of document.querySelectorAll('meta[name^="citation_"]')) {
|
|
12641
|
+
const name = el.getAttribute("name") || "";
|
|
12642
|
+
const content = el.getAttribute("content") || "";
|
|
12643
|
+
if (!citationMulti[name]) citationMulti[name] = [];
|
|
12644
|
+
citationMulti[name].push(content);
|
|
12645
|
+
}
|
|
12646
|
+
const citation = {};
|
|
12647
|
+
for (const [key, values] of Object.entries(citationMulti)) {
|
|
12648
|
+
citation[key] = values.length === 1 ? values[0] : values;
|
|
12649
|
+
}
|
|
12650
|
+
|
|
12651
|
+
const dcMulti = {};
|
|
12652
|
+
for (const el of document.querySelectorAll('meta[name^="DC."]')) {
|
|
12653
|
+
const name = el.getAttribute("name") || "";
|
|
12654
|
+
const content = el.getAttribute("content") || "";
|
|
12655
|
+
if (!dcMulti[name]) dcMulti[name] = [];
|
|
12656
|
+
dcMulti[name].push(content);
|
|
12657
|
+
}
|
|
12658
|
+
const dc = {};
|
|
12659
|
+
for (const [key, values] of Object.entries(dcMulti)) {
|
|
12660
|
+
dc[key] = values.length === 1 ? values[0] : values;
|
|
12661
|
+
}
|
|
12662
|
+
const og = Object.fromEntries(
|
|
12663
|
+
[...document.querySelectorAll('meta[property^="og:"]')]
|
|
12664
|
+
.map(el => [el.getAttribute("property"), el.getAttribute("content") || ""])
|
|
12665
|
+
.filter(([k]) => k));
|
|
12666
|
+
return { jsonLd, citation, dc, og, title: document.title };
|
|
12667
|
+
})()
|
|
12668
|
+
`);
|
|
12669
|
+
const pageUrl = page.url();
|
|
12670
|
+
const jsonLdFields = extractFromJsonLd(rawMeta.jsonLd);
|
|
12671
|
+
const citationFields = extractFromCitation(rawMeta.citation);
|
|
12672
|
+
const dcFields = extractFromDublinCore(rawMeta.dc);
|
|
12673
|
+
const ogFields = extractFromOpenGraph(rawMeta.og);
|
|
12674
|
+
const htmlFields = {};
|
|
12675
|
+
if (rawMeta.title) htmlFields.title = rawMeta.title;
|
|
12676
|
+
const merged = mergeFields(jsonLdFields, citationFields, dcFields, ogFields, htmlFields);
|
|
12677
|
+
const now = /* @__PURE__ */ new Date();
|
|
12678
|
+
const accessed = {
|
|
12679
|
+
"date-parts": [[now.getFullYear(), now.getMonth() + 1, now.getDate()]]
|
|
12680
|
+
};
|
|
12681
|
+
const item = {
|
|
12682
|
+
id: "",
|
|
12683
|
+
type: merged.type || "webpage",
|
|
12684
|
+
title: merged.title || pageUrl,
|
|
12685
|
+
URL: pageUrl,
|
|
12686
|
+
accessed
|
|
12687
|
+
};
|
|
12688
|
+
if (merged.author?.length) item.author = merged.author;
|
|
12689
|
+
if (merged.issued) item.issued = merged.issued;
|
|
12690
|
+
if (merged.DOI) item.DOI = merged.DOI;
|
|
12691
|
+
if (merged["container-title"]) item["container-title"] = merged["container-title"];
|
|
12692
|
+
if (merged.publisher) item.publisher = merged.publisher;
|
|
12693
|
+
if (merged.abstract) item.abstract = merged.abstract;
|
|
12694
|
+
return item;
|
|
12695
|
+
}
|
|
12696
|
+
function getReadabilityPath() {
|
|
12697
|
+
const require2 = createRequire(import.meta.url);
|
|
12698
|
+
return require2.resolve("@mozilla/readability/Readability.js");
|
|
12699
|
+
}
|
|
12700
|
+
let readabilityScriptCache;
|
|
12701
|
+
function getReadabilityScript() {
|
|
12702
|
+
if (readabilityScriptCache === void 0) {
|
|
12703
|
+
readabilityScriptCache = readFileSync(getReadabilityPath(), "utf-8");
|
|
12704
|
+
}
|
|
12705
|
+
return readabilityScriptCache;
|
|
12706
|
+
}
|
|
12707
|
+
async function processPage(page, url, options) {
|
|
12708
|
+
const warnings = [];
|
|
12709
|
+
await page.goto(url, {
|
|
12710
|
+
waitUntil: "domcontentloaded",
|
|
12711
|
+
timeout: options.timeout * 1e3
|
|
12712
|
+
});
|
|
12713
|
+
await page.waitForLoadState("networkidle", { timeout: 2e3 }).catch(() => {
|
|
12714
|
+
});
|
|
12715
|
+
try {
|
|
12716
|
+
const readabilityScript = getReadabilityScript();
|
|
12717
|
+
await page.addScriptTag({ content: readabilityScript });
|
|
12718
|
+
} catch (error) {
|
|
12719
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
12720
|
+
warnings.push(`Readability injection failed: ${msg}`);
|
|
12721
|
+
}
|
|
12722
|
+
const item = await extractMetadata(page);
|
|
12723
|
+
const fulltext = await generateFulltext(page);
|
|
12724
|
+
let archive;
|
|
12725
|
+
if (!options.noArchive) {
|
|
12726
|
+
try {
|
|
12727
|
+
archive = await createArchive(page, options.archiveFormat);
|
|
12728
|
+
} catch (error) {
|
|
12729
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
12730
|
+
warnings.push(`Archive creation failed: ${msg}`);
|
|
12731
|
+
}
|
|
12732
|
+
}
|
|
12733
|
+
return { item, fulltext, archive, warnings };
|
|
12734
|
+
}
|
|
12735
|
+
function resolvePageOptions(options) {
|
|
12736
|
+
return {
|
|
12737
|
+
archiveFormat: options.archiveFormat ?? options.urlConfig.archiveFormat,
|
|
12738
|
+
noArchive: options.noArchive ?? false,
|
|
12739
|
+
timeout: options.urlConfig.timeout
|
|
12740
|
+
};
|
|
12741
|
+
}
|
|
12742
|
+
async function fetchUrl(url, options) {
|
|
12743
|
+
const browser = await launchBrowser(options.urlConfig);
|
|
12744
|
+
try {
|
|
12745
|
+
const page = await browser.newPage();
|
|
12746
|
+
try {
|
|
12747
|
+
return await processPage(page, url, resolvePageOptions(options));
|
|
12748
|
+
} finally {
|
|
12749
|
+
await page.close();
|
|
12750
|
+
}
|
|
12751
|
+
} finally {
|
|
12752
|
+
await browser.close();
|
|
12753
|
+
}
|
|
12754
|
+
}
|
|
12755
|
+
async function fetchUrls(urls, options) {
|
|
12756
|
+
const results = /* @__PURE__ */ new Map();
|
|
12757
|
+
if (urls.length === 0) {
|
|
12758
|
+
return results;
|
|
12759
|
+
}
|
|
12760
|
+
let browser;
|
|
12761
|
+
try {
|
|
12762
|
+
browser = await launchBrowser(options.urlConfig);
|
|
12763
|
+
} catch (error) {
|
|
12764
|
+
for (const url of urls) {
|
|
12765
|
+
results.set(url, error instanceof Error ? error : new Error(String(error)));
|
|
12766
|
+
}
|
|
12767
|
+
return results;
|
|
12768
|
+
}
|
|
12769
|
+
const pageOptions = resolvePageOptions(options);
|
|
12770
|
+
try {
|
|
12771
|
+
for (const url of urls) {
|
|
12772
|
+
try {
|
|
12773
|
+
const page = await browser.newPage();
|
|
12774
|
+
try {
|
|
12775
|
+
const result = await processPage(page, url, pageOptions);
|
|
12776
|
+
results.set(url, result);
|
|
12777
|
+
} finally {
|
|
12778
|
+
await page.close();
|
|
12779
|
+
}
|
|
12780
|
+
} catch (error) {
|
|
12781
|
+
results.set(url, error instanceof Error ? error : new Error(String(error)));
|
|
12782
|
+
}
|
|
12783
|
+
}
|
|
12784
|
+
} finally {
|
|
12785
|
+
await browser.close();
|
|
12786
|
+
}
|
|
12787
|
+
return results;
|
|
12788
|
+
}
|
|
12309
12789
|
function classifyIdentifiers(identifiers) {
|
|
12310
12790
|
const pmids = [];
|
|
12311
12791
|
const dois = [];
|
|
@@ -12642,10 +13122,104 @@ async function processFile(filePath, options) {
|
|
|
12642
13122
|
];
|
|
12643
13123
|
}
|
|
12644
13124
|
}
|
|
13125
|
+
async function processUrlInput(url, options) {
|
|
13126
|
+
if (!options.urlConfig) {
|
|
13127
|
+
return {
|
|
13128
|
+
success: false,
|
|
13129
|
+
error: "URL import requires browser configuration. Set [url] section in config.",
|
|
13130
|
+
source: url,
|
|
13131
|
+
reason: "validation_error"
|
|
13132
|
+
};
|
|
13133
|
+
}
|
|
13134
|
+
try {
|
|
13135
|
+
const result = await fetchUrl(url, {
|
|
13136
|
+
urlConfig: options.urlConfig,
|
|
13137
|
+
archiveFormat: options.archiveFormat,
|
|
13138
|
+
noArchive: options.noArchive
|
|
13139
|
+
});
|
|
13140
|
+
return {
|
|
13141
|
+
success: true,
|
|
13142
|
+
item: result.item,
|
|
13143
|
+
source: url,
|
|
13144
|
+
urlData: {
|
|
13145
|
+
fulltext: result.fulltext,
|
|
13146
|
+
archive: result.archive,
|
|
13147
|
+
warnings: result.warnings
|
|
13148
|
+
}
|
|
13149
|
+
};
|
|
13150
|
+
} catch (error) {
|
|
13151
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
13152
|
+
return {
|
|
13153
|
+
success: false,
|
|
13154
|
+
error: message,
|
|
13155
|
+
source: url,
|
|
13156
|
+
reason: "fetch_error"
|
|
13157
|
+
};
|
|
13158
|
+
}
|
|
13159
|
+
}
|
|
13160
|
+
async function processUrlInputs(urls, options) {
|
|
13161
|
+
if (!options.urlConfig) {
|
|
13162
|
+
return urls.map((url) => ({
|
|
13163
|
+
success: false,
|
|
13164
|
+
error: "URL import requires browser configuration. Set [url] section in config.",
|
|
13165
|
+
source: url,
|
|
13166
|
+
reason: "validation_error"
|
|
13167
|
+
}));
|
|
13168
|
+
}
|
|
13169
|
+
if (urls.length === 1) {
|
|
13170
|
+
const url = urls[0];
|
|
13171
|
+
if (url) return [await processUrlInput(url, options)];
|
|
13172
|
+
return [];
|
|
13173
|
+
}
|
|
13174
|
+
const fetchResults = await fetchUrls(urls, {
|
|
13175
|
+
urlConfig: options.urlConfig,
|
|
13176
|
+
archiveFormat: options.archiveFormat,
|
|
13177
|
+
noArchive: options.noArchive
|
|
13178
|
+
});
|
|
13179
|
+
return urls.map((url) => {
|
|
13180
|
+
const result = fetchResults.get(url);
|
|
13181
|
+
if (!result) {
|
|
13182
|
+
return {
|
|
13183
|
+
success: false,
|
|
13184
|
+
error: "URL was not processed",
|
|
13185
|
+
source: url,
|
|
13186
|
+
reason: "fetch_error"
|
|
13187
|
+
};
|
|
13188
|
+
}
|
|
13189
|
+
if (result instanceof Error) {
|
|
13190
|
+
return {
|
|
13191
|
+
success: false,
|
|
13192
|
+
error: result.message,
|
|
13193
|
+
source: url,
|
|
13194
|
+
reason: "fetch_error"
|
|
13195
|
+
};
|
|
13196
|
+
}
|
|
13197
|
+
return {
|
|
13198
|
+
success: true,
|
|
13199
|
+
item: result.item,
|
|
13200
|
+
source: url,
|
|
13201
|
+
urlData: {
|
|
13202
|
+
fulltext: result.fulltext,
|
|
13203
|
+
archive: result.archive,
|
|
13204
|
+
warnings: result.warnings
|
|
13205
|
+
}
|
|
13206
|
+
};
|
|
13207
|
+
});
|
|
13208
|
+
}
|
|
12645
13209
|
async function processIdentifiers(inputs, options) {
|
|
12646
13210
|
const results = [];
|
|
12647
13211
|
const validIdentifiers = [];
|
|
13212
|
+
const urlInputs = [];
|
|
12648
13213
|
for (const input of inputs) {
|
|
13214
|
+
const pubmedId = extractPubmedId(input);
|
|
13215
|
+
if (pubmedId !== null) {
|
|
13216
|
+
validIdentifiers.push(pubmedId);
|
|
13217
|
+
continue;
|
|
13218
|
+
}
|
|
13219
|
+
if (isUrl(input)) {
|
|
13220
|
+
urlInputs.push(input);
|
|
13221
|
+
continue;
|
|
13222
|
+
}
|
|
12649
13223
|
const isValidPmid = isPmid(input);
|
|
12650
13224
|
const isValidDoi = isDoi(input);
|
|
12651
13225
|
const isValidIsbn = isIsbn(input);
|
|
@@ -12666,6 +13240,10 @@ async function processIdentifiers(inputs, options) {
|
|
|
12666
13240
|
const fetchResult = await importFromIdentifiers(validIdentifiers, options);
|
|
12667
13241
|
results.push(...fetchResult.results);
|
|
12668
13242
|
}
|
|
13243
|
+
if (urlInputs.length > 0) {
|
|
13244
|
+
const urlResults = await processUrlInputs(urlInputs, options);
|
|
13245
|
+
results.push(...urlResults);
|
|
13246
|
+
}
|
|
12669
13247
|
return results;
|
|
12670
13248
|
}
|
|
12671
13249
|
async function importFromInputs(inputs, options) {
|
|
@@ -12736,17 +13314,40 @@ async function addReferences(inputs, library, options) {
|
|
|
12736
13314
|
);
|
|
12737
13315
|
if (processed.type === "failed") {
|
|
12738
13316
|
failed.push(processed.item);
|
|
12739
|
-
|
|
13317
|
+
continue;
|
|
13318
|
+
}
|
|
13319
|
+
if (processed.type === "skipped") {
|
|
12740
13320
|
skipped.push(processed.item);
|
|
12741
|
-
|
|
12742
|
-
added.push(processed.item);
|
|
13321
|
+
continue;
|
|
12743
13322
|
}
|
|
13323
|
+
if (result.success && result.urlData) {
|
|
13324
|
+
await handleUrlData(processed.item, result.urlData, library, options.attachmentsDirectory);
|
|
13325
|
+
}
|
|
13326
|
+
added.push(processed.item);
|
|
12744
13327
|
}
|
|
12745
13328
|
if (added.length > 0) {
|
|
12746
13329
|
await library.save();
|
|
12747
13330
|
}
|
|
12748
13331
|
return { added, failed, skipped };
|
|
12749
13332
|
}
|
|
13333
|
+
async function handleUrlData(addedItem, urlData, library, attachmentsDirectory) {
|
|
13334
|
+
if (urlData.warnings.length > 0) {
|
|
13335
|
+
addedItem.warnings = [...urlData.warnings];
|
|
13336
|
+
}
|
|
13337
|
+
if (attachmentsDirectory) {
|
|
13338
|
+
try {
|
|
13339
|
+
await saveUrlData(addedItem.id, urlData, library, attachmentsDirectory);
|
|
13340
|
+
} catch (error) {
|
|
13341
|
+
const message = `Failed to save URL data for ${addedItem.id}: ${error instanceof Error ? error.message : String(error)}`;
|
|
13342
|
+
process.stderr.write(`${message}
|
|
13343
|
+
`);
|
|
13344
|
+
if (!addedItem.warnings) {
|
|
13345
|
+
addedItem.warnings = [];
|
|
13346
|
+
}
|
|
13347
|
+
addedItem.warnings.push(message);
|
|
13348
|
+
}
|
|
13349
|
+
}
|
|
13350
|
+
}
|
|
12750
13351
|
function buildImportOptions(options) {
|
|
12751
13352
|
const importOptions = {};
|
|
12752
13353
|
if (options.format !== void 0) {
|
|
@@ -12758,6 +13359,15 @@ function buildImportOptions(options) {
|
|
|
12758
13359
|
if (options.stdinContent !== void 0) {
|
|
12759
13360
|
importOptions.stdinContent = options.stdinContent;
|
|
12760
13361
|
}
|
|
13362
|
+
if (options.urlConfig !== void 0) {
|
|
13363
|
+
importOptions.urlConfig = options.urlConfig;
|
|
13364
|
+
}
|
|
13365
|
+
if (options.archiveFormat !== void 0) {
|
|
13366
|
+
importOptions.archiveFormat = options.archiveFormat;
|
|
13367
|
+
}
|
|
13368
|
+
if (options.noArchive !== void 0) {
|
|
13369
|
+
importOptions.noArchive = options.noArchive;
|
|
13370
|
+
}
|
|
12761
13371
|
return importOptions;
|
|
12762
13372
|
}
|
|
12763
13373
|
async function processImportResult(result, existingItems, addedIds, force, library) {
|
|
@@ -12803,6 +13413,52 @@ async function processImportResult(result, existingItems, addedIds, force, libra
|
|
|
12803
13413
|
}
|
|
12804
13414
|
return { type: "added", item: addedItem };
|
|
12805
13415
|
}
|
|
13416
|
+
async function saveUrlData(id, urlData, library, attachmentsDirectory) {
|
|
13417
|
+
if (urlData.fulltext) {
|
|
13418
|
+
let tempDir;
|
|
13419
|
+
try {
|
|
13420
|
+
tempDir = mkdtempSync(join(tmpdir(), "refmgr-url-ft-"));
|
|
13421
|
+
const fulltextPath = join(tempDir, "fulltext.md");
|
|
13422
|
+
writeFileSync(fulltextPath, urlData.fulltext, "utf-8");
|
|
13423
|
+
await addAttachment(library, {
|
|
13424
|
+
identifier: id,
|
|
13425
|
+
filePath: fulltextPath,
|
|
13426
|
+
role: "fulltext",
|
|
13427
|
+
move: true,
|
|
13428
|
+
force: true,
|
|
13429
|
+
idType: "id",
|
|
13430
|
+
attachmentsDirectory
|
|
13431
|
+
});
|
|
13432
|
+
} finally {
|
|
13433
|
+
if (tempDir) {
|
|
13434
|
+
await rm(tempDir, { recursive: true, force: true }).catch(() => {
|
|
13435
|
+
});
|
|
13436
|
+
}
|
|
13437
|
+
}
|
|
13438
|
+
}
|
|
13439
|
+
if (urlData.archive) {
|
|
13440
|
+
let tempDir;
|
|
13441
|
+
try {
|
|
13442
|
+
tempDir = mkdtempSync(join(tmpdir(), "refmgr-url-ar-"));
|
|
13443
|
+
const archivePath = join(tempDir, `archive.${urlData.archive.extension}`);
|
|
13444
|
+
writeFileSync(archivePath, urlData.archive.data, "utf-8");
|
|
13445
|
+
await addAttachment(library, {
|
|
13446
|
+
identifier: id,
|
|
13447
|
+
filePath: archivePath,
|
|
13448
|
+
role: "archive",
|
|
13449
|
+
move: true,
|
|
13450
|
+
force: false,
|
|
13451
|
+
idType: "id",
|
|
13452
|
+
attachmentsDirectory
|
|
13453
|
+
});
|
|
13454
|
+
} finally {
|
|
13455
|
+
if (tempDir) {
|
|
13456
|
+
await rm(tempDir, { recursive: true, force: true }).catch(() => {
|
|
13457
|
+
});
|
|
13458
|
+
}
|
|
13459
|
+
}
|
|
13460
|
+
}
|
|
13461
|
+
}
|
|
12806
13462
|
function generateSuffix(index) {
|
|
12807
13463
|
const alphabet = "abcdefghijklmnopqrstuvwxyz";
|
|
12808
13464
|
let suffix = "";
|
|
@@ -12873,7 +13529,7 @@ function createAddRoute(library, config) {
|
|
|
12873
13529
|
}
|
|
12874
13530
|
const CHECK_CONCURRENCY = 5;
|
|
12875
13531
|
async function checkReferences(library, options) {
|
|
12876
|
-
const { checkReference } = await import("./checker-
|
|
13532
|
+
const { checkReference } = await import("./checker-CnWQe7v2.js");
|
|
12877
13533
|
const save = options.save !== false;
|
|
12878
13534
|
const skipDays = options.skipDays ?? 7;
|
|
12879
13535
|
const items = await resolveItems(library, options);
|
|
@@ -13566,4 +14222,4 @@ export {
|
|
|
13566
14222
|
createServer as y,
|
|
13567
14223
|
fetch$1 as z
|
|
13568
14224
|
};
|
|
13569
|
-
//# sourceMappingURL=index-
|
|
14225
|
+
//# sourceMappingURL=index-a52FHX03.js.map
|