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