@zenalexa/unicli 0.225.2 → 0.225.3
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/AGENTS.md +2 -2
- package/README.md +3 -3
- package/README.zh-CN.md +3 -3
- package/dist/adapters/acl-anthology/papers.d.ts +16 -9
- package/dist/adapters/acl-anthology/papers.d.ts.map +1 -1
- package/dist/adapters/acl-anthology/papers.js +322 -58
- package/dist/adapters/acl-anthology/papers.js.map +1 -1
- package/dist/adapters/arxiv/papers.d.ts +22 -4
- package/dist/adapters/arxiv/papers.d.ts.map +1 -1
- package/dist/adapters/arxiv/papers.js +202 -4
- package/dist/adapters/arxiv/papers.js.map +1 -1
- package/dist/adapters/baidu-scholar/search.d.ts +15 -1
- package/dist/adapters/baidu-scholar/search.d.ts.map +1 -1
- package/dist/adapters/baidu-scholar/search.js +72 -8
- package/dist/adapters/baidu-scholar/search.js.map +1 -1
- package/dist/adapters/biorxiv/preprints.d.ts +9 -0
- package/dist/adapters/biorxiv/preprints.d.ts.map +1 -0
- package/dist/adapters/biorxiv/preprints.js +78 -0
- package/dist/adapters/biorxiv/preprints.js.map +1 -0
- package/dist/adapters/cnki/search.d.ts +82 -0
- package/dist/adapters/cnki/search.d.ts.map +1 -0
- package/dist/adapters/cnki/search.js +236 -0
- package/dist/adapters/cnki/search.js.map +1 -0
- package/dist/adapters/cvf/papers.d.ts +12 -7
- package/dist/adapters/cvf/papers.d.ts.map +1 -1
- package/dist/adapters/cvf/papers.js +210 -27
- package/dist/adapters/cvf/papers.js.map +1 -1
- package/dist/adapters/dblp/publications.d.ts +12 -5
- package/dist/adapters/dblp/publications.d.ts.map +1 -1
- package/dist/adapters/dblp/publications.js +31 -8
- package/dist/adapters/dblp/publications.js.map +1 -1
- package/dist/adapters/google-scholar/search.d.ts +22 -1
- package/dist/adapters/google-scholar/search.d.ts.map +1 -1
- package/dist/adapters/google-scholar/search.js +129 -14
- package/dist/adapters/google-scholar/search.js.map +1 -1
- package/dist/adapters/hf/paper.d.ts +12 -3
- package/dist/adapters/hf/paper.d.ts.map +1 -1
- package/dist/adapters/hf/paper.js +65 -5
- package/dist/adapters/hf/paper.js.map +1 -1
- package/dist/adapters/medrxiv/preprints.d.ts +9 -0
- package/dist/adapters/medrxiv/preprints.d.ts.map +1 -0
- package/dist/adapters/medrxiv/preprints.js +78 -0
- package/dist/adapters/medrxiv/preprints.js.map +1 -0
- package/dist/adapters/neurips/proceedings.d.ts +8 -7
- package/dist/adapters/neurips/proceedings.d.ts.map +1 -1
- package/dist/adapters/neurips/proceedings.js +209 -21
- package/dist/adapters/neurips/proceedings.js.map +1 -1
- package/dist/adapters/openalex/works.d.ts +21 -5
- package/dist/adapters/openalex/works.d.ts.map +1 -1
- package/dist/adapters/openalex/works.js +108 -8
- package/dist/adapters/openalex/works.js.map +1 -1
- package/dist/adapters/openreview/papers.d.ts +10 -4
- package/dist/adapters/openreview/papers.d.ts.map +1 -1
- package/dist/adapters/openreview/papers.js +351 -24
- package/dist/adapters/openreview/papers.js.map +1 -1
- package/dist/adapters/pmlr/proceedings.d.ts +6 -6
- package/dist/adapters/pmlr/proceedings.d.ts.map +1 -1
- package/dist/adapters/pmlr/proceedings.js +92 -12
- package/dist/adapters/pmlr/proceedings.js.map +1 -1
- package/dist/adapters/pubmed/articles.d.ts +8 -4
- package/dist/adapters/pubmed/articles.d.ts.map +1 -1
- package/dist/adapters/pubmed/articles.js +272 -39
- package/dist/adapters/pubmed/articles.js.map +1 -1
- package/dist/adapters/rxiv/preprints.d.ts +75 -0
- package/dist/adapters/rxiv/preprints.d.ts.map +1 -0
- package/dist/adapters/rxiv/preprints.js +651 -0
- package/dist/adapters/rxiv/preprints.js.map +1 -0
- package/dist/adapters/scholar-artifacts/pdf-read.d.ts +49 -0
- package/dist/adapters/scholar-artifacts/pdf-read.d.ts.map +1 -0
- package/dist/adapters/scholar-artifacts/pdf-read.js +204 -0
- package/dist/adapters/scholar-artifacts/pdf-read.js.map +1 -0
- package/dist/adapters/scholar-artifacts/pdf.d.ts +16 -0
- package/dist/adapters/scholar-artifacts/pdf.d.ts.map +1 -0
- package/dist/adapters/scholar-artifacts/pdf.js +122 -0
- package/dist/adapters/scholar-artifacts/pdf.js.map +1 -0
- package/dist/adapters/semantic-scholar/papers.d.ts +6 -6
- package/dist/adapters/semantic-scholar/papers.d.ts.map +1 -1
- package/dist/adapters/semantic-scholar/papers.js +80 -6
- package/dist/adapters/semantic-scholar/papers.js.map +1 -1
- package/dist/adapters/unpaywall/works.d.ts +7 -7
- package/dist/adapters/unpaywall/works.d.ts.map +1 -1
- package/dist/adapters/unpaywall/works.js +104 -12
- package/dist/adapters/unpaywall/works.js.map +1 -1
- package/dist/adapters/wanfang/search.d.ts +14 -0
- package/dist/adapters/wanfang/search.d.ts.map +1 -1
- package/dist/adapters/wanfang/search.js +56 -7
- package/dist/adapters/wanfang/search.js.map +1 -1
- package/dist/browser/page.d.ts +2 -0
- package/dist/browser/page.d.ts.map +1 -1
- package/dist/browser/page.js +12 -0
- package/dist/browser/page.js.map +1 -1
- package/dist/commands/browser/actions.d.ts.map +1 -1
- package/dist/commands/browser/actions.js +59 -3
- package/dist/commands/browser/actions.js.map +1 -1
- package/dist/commands/scholar.d.ts +77 -5
- package/dist/commands/scholar.d.ts.map +1 -1
- package/dist/commands/scholar.js +2945 -83
- package/dist/commands/scholar.js.map +1 -1
- package/dist/core/command-contract.d.ts.map +1 -1
- package/dist/core/command-contract.js +5 -0
- package/dist/core/command-contract.js.map +1 -1
- package/dist/core/schema-v2.d.ts +1 -0
- package/dist/core/schema-v2.d.ts.map +1 -1
- package/dist/core/schema-v2.js +1 -0
- package/dist/core/schema-v2.js.map +1 -1
- package/dist/discovery/aliases.d.ts.map +1 -1
- package/dist/discovery/aliases.js +208 -0
- package/dist/discovery/aliases.js.map +1 -1
- package/dist/discovery/core-catalog.d.ts +2 -0
- package/dist/discovery/core-catalog.d.ts.map +1 -1
- package/dist/discovery/core-catalog.js +487 -0
- package/dist/discovery/core-catalog.js.map +1 -1
- package/dist/discovery/intents.d.ts.map +1 -1
- package/dist/discovery/intents.js +273 -2
- package/dist/discovery/intents.js.map +1 -1
- package/dist/discovery/loader.d.ts.map +1 -1
- package/dist/discovery/loader.js +3 -0
- package/dist/discovery/loader.js.map +1 -1
- package/dist/engine/capability-policy.d.ts.map +1 -1
- package/dist/engine/capability-policy.js +30 -4
- package/dist/engine/capability-policy.js.map +1 -1
- package/dist/engine/kernel/stages.d.ts.map +1 -1
- package/dist/engine/kernel/stages.js +3 -0
- package/dist/engine/kernel/stages.js.map +1 -1
- package/dist/engine/operation-policy.d.ts +4 -1
- package/dist/engine/operation-policy.d.ts.map +1 -1
- package/dist/engine/operation-policy.js +23 -0
- package/dist/engine/operation-policy.js.map +1 -1
- package/dist/fast-path/manifest.d.ts +3 -0
- package/dist/fast-path/manifest.d.ts.map +1 -1
- package/dist/fast-path/manifest.js.map +1 -1
- package/dist/fast-path/policy.d.ts.map +1 -1
- package/dist/fast-path/policy.js +3 -0
- package/dist/fast-path/policy.js.map +1 -1
- package/dist/manifest-compact.txt +1 -1
- package/dist/manifest.json +6804 -1002
- package/dist/registry.d.ts +2 -0
- package/dist/registry.d.ts.map +1 -1
- package/dist/registry.js +1 -0
- package/dist/registry.js.map +1 -1
- package/dist/types/scholarly.d.ts +19 -4
- package/dist/types/scholarly.d.ts.map +1 -1
- package/dist/types/scholarly.js +4 -4
- package/dist/types.d.ts +8 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +1 -1
- package/server.json +2 -2
- package/skills/unicli/SKILL.md +1 -1
- package/skills/unicli-claude-code/SKILL.md +1 -1
- package/skills/unicli-hermes/SKILL.md +1 -1
- package/src/adapters/acl-anthology/papers.test.ts +111 -0
- package/src/adapters/acl-anthology/papers.ts +379 -71
- package/src/adapters/arxiv/papers.test.ts +46 -0
- package/src/adapters/arxiv/papers.ts +251 -4
- package/src/adapters/baidu-scholar/search.ts +74 -11
- package/src/adapters/biorxiv/preprints.ts +112 -0
- package/src/adapters/cnki/search.ts +357 -0
- package/src/adapters/cvf/papers.ts +260 -27
- package/src/adapters/dblp/publications.test.ts +9 -0
- package/src/adapters/dblp/publications.ts +31 -8
- package/src/adapters/google-scholar/search.ts +165 -17
- package/src/adapters/hf/paper.test.ts +23 -0
- package/src/adapters/hf/paper.ts +89 -5
- package/src/adapters/hf/top.yaml +34 -2
- package/src/adapters/huggingface-papers/daily.yaml +37 -3
- package/src/adapters/huggingface-papers/search.yaml +43 -9
- package/src/adapters/medrxiv/preprints.ts +112 -0
- package/src/adapters/neurips/proceedings.ts +266 -22
- package/src/adapters/openalex/works.test.ts +15 -4
- package/src/adapters/openalex/works.ts +136 -8
- package/src/adapters/openreview/papers.test.ts +31 -0
- package/src/adapters/openreview/papers.ts +407 -29
- package/src/adapters/pmlr/proceedings.ts +102 -12
- package/src/adapters/pubmed/articles.test.ts +88 -1
- package/src/adapters/pubmed/articles.ts +343 -44
- package/src/adapters/rxiv/preprints.test.ts +233 -0
- package/src/adapters/rxiv/preprints.ts +849 -0
- package/src/adapters/scholar-artifacts/pdf-read.ts +277 -0
- package/src/adapters/scholar-artifacts/pdf.ts +133 -0
- package/src/adapters/semantic-scholar/papers.ts +98 -6
- package/src/adapters/unpaywall/works.ts +141 -12
- package/src/adapters/wanfang/search.ts +57 -7
- package/src/adapters/cnki/search.yaml +0 -49
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @owner src::adapters::pmlr::proceedings
|
|
3
|
-
* @does Registers Proceedings of Machine Learning Research volume search using official citeproc.yaml metadata.
|
|
4
|
-
* @needs proceedings.mlr.press citeproc.yaml
|
|
5
|
-
* @feeds src/commands/scholar.ts via scholar.search, scholar.get, scholar.pdf, and scholar.venue
|
|
6
|
-
* @breaks Missing volume metadata
|
|
3
|
+
* @does Registers Proceedings of Machine Learning Research volume search, paper lookup, and PDF text reading using official citeproc.yaml metadata.
|
|
4
|
+
* @needs proceedings.mlr.press citeproc.yaml/PDF assets, js-yaml, src/adapters/scholar-artifacts/pdf-read.ts, src/registry.ts
|
|
5
|
+
* @feeds src/commands/scholar.ts via scholar.search, scholar.get, scholar.pdf, scholar.fulltext, and scholar.venue
|
|
6
|
+
* @breaks Missing volume metadata, citeproc/PDF drift, denied downloads, or missing pdftotext surfaces as explicit adapter errors.
|
|
7
7
|
* @invariants Volume is explicit; rows are filtered locally from official YAML metadata, not scraped from rendered cards.
|
|
8
|
-
* @side-effects HTTPS egress to proceedings.mlr.press
|
|
9
|
-
* @perf O(N) over one proceedings volume
|
|
8
|
+
* @side-effects HTTPS egress to proceedings.mlr.press/raw.githubusercontent.com; read writes one PDF artifact and executes pdftotext.
|
|
9
|
+
* @perf O(N) over one proceedings volume; read is O(PDF bytes + selected pages)
|
|
10
10
|
* @concurrency safe
|
|
11
11
|
* @test tests/unit/adapters/scholar-sources.test.ts
|
|
12
12
|
* @stability experimental
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"proceedings.d.ts","sourceRoot":"","sources":["../../../src/adapters/pmlr/proceedings.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAIH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;
|
|
1
|
+
{"version":3,"file":"proceedings.d.ts","sourceRoot":"","sources":["../../../src/adapters/pmlr/proceedings.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAIH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAGpE,UAAU,SAAS;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,MAAM,CAAC,EAAE,KAAK,CAAC;QAAE,KAAK,CAAC,EAAE,OAAO,CAAC;QAAC,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;IACtD,EAAE,CAAC,EAAE,OAAO,CAAC;IACb,MAAM,CAAC,EAAE;QAAE,YAAY,CAAC,EAAE,OAAO,EAAE,CAAA;KAAE,CAAC;IACtC,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAuBD,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,EAAE,CAG3D;AAED,wBAAgB,YAAY,CAC1B,KAAK,EAAE,SAAS,EAChB,MAAM,EAAE,MAAM,GACb,mBAAmB,CAgBrB"}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @owner src::adapters::pmlr::proceedings
|
|
3
|
-
* @does Registers Proceedings of Machine Learning Research volume search using official citeproc.yaml metadata.
|
|
4
|
-
* @needs proceedings.mlr.press citeproc.yaml
|
|
5
|
-
* @feeds src/commands/scholar.ts via scholar.search, scholar.get, scholar.pdf, and scholar.venue
|
|
6
|
-
* @breaks Missing volume metadata
|
|
3
|
+
* @does Registers Proceedings of Machine Learning Research volume search, paper lookup, and PDF text reading using official citeproc.yaml metadata.
|
|
4
|
+
* @needs proceedings.mlr.press citeproc.yaml/PDF assets, js-yaml, src/adapters/scholar-artifacts/pdf-read.ts, src/registry.ts
|
|
5
|
+
* @feeds src/commands/scholar.ts via scholar.search, scholar.get, scholar.pdf, scholar.fulltext, and scholar.venue
|
|
6
|
+
* @breaks Missing volume metadata, citeproc/PDF drift, denied downloads, or missing pdftotext surfaces as explicit adapter errors.
|
|
7
7
|
* @invariants Volume is explicit; rows are filtered locally from official YAML metadata, not scraped from rendered cards.
|
|
8
|
-
* @side-effects HTTPS egress to proceedings.mlr.press
|
|
9
|
-
* @perf O(N) over one proceedings volume
|
|
8
|
+
* @side-effects HTTPS egress to proceedings.mlr.press/raw.githubusercontent.com; read writes one PDF artifact and executes pdftotext.
|
|
9
|
+
* @perf O(N) over one proceedings volume; read is O(PDF bytes + selected pages)
|
|
10
10
|
* @concurrency safe
|
|
11
11
|
* @test tests/unit/adapters/scholar-sources.test.ts
|
|
12
12
|
* @stability experimental
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
*/
|
|
15
15
|
import yaml from "js-yaml";
|
|
16
16
|
import { cli, Strategy } from "../../registry.js";
|
|
17
|
+
import { readScholarPdf } from "../scholar-artifacts/pdf-read.js";
|
|
17
18
|
function str(value) {
|
|
18
19
|
return typeof value === "string" ? value.trim() : "";
|
|
19
20
|
}
|
|
@@ -74,6 +75,35 @@ async function fetchVolume(volume) {
|
|
|
74
75
|
throw new Error(`PMLR volume v${volume} returned HTTP ${response.status}.`);
|
|
75
76
|
return parsePmlrCiteproc(await response.text());
|
|
76
77
|
}
|
|
78
|
+
async function findPmlrPaper(volume, id) {
|
|
79
|
+
const row = (await fetchVolume(volume))
|
|
80
|
+
.map((entry) => mapPmlrEntry(entry, "pmlr"))
|
|
81
|
+
.find((entry) => entry.id === id);
|
|
82
|
+
if (!row)
|
|
83
|
+
throw new Error(`No PMLR v${volume} paper found with id "${id}".`);
|
|
84
|
+
return row;
|
|
85
|
+
}
|
|
86
|
+
async function readPmlrPaperPdf(row, kwargs) {
|
|
87
|
+
if (!row.pdf_url)
|
|
88
|
+
throw new Error(`PMLR paper ${row.id} has no PDF URL.`);
|
|
89
|
+
return readScholarPdf({
|
|
90
|
+
id: row.id,
|
|
91
|
+
title: row.title,
|
|
92
|
+
source_adapter: "pmlr",
|
|
93
|
+
source_url: row.source_url,
|
|
94
|
+
pdf_url: row.pdf_url,
|
|
95
|
+
output: kwargs.output,
|
|
96
|
+
filename: kwargs.filename,
|
|
97
|
+
"first-page": kwargs["first-page"] ?? kwargs.firstPage,
|
|
98
|
+
"last-page": kwargs["last-page"] ?? kwargs.lastPage,
|
|
99
|
+
"max-chars": kwargs["max-chars"] ?? kwargs.maxChars,
|
|
100
|
+
}, {
|
|
101
|
+
site: "pmlr",
|
|
102
|
+
command: "read",
|
|
103
|
+
defaultOutput: "./pmlr-downloads",
|
|
104
|
+
userAgent: "unicli-pmlr/1.0 (https://github.com/olo-dot-io/Uni-CLI)",
|
|
105
|
+
});
|
|
106
|
+
}
|
|
77
107
|
cli({
|
|
78
108
|
site: "pmlr",
|
|
79
109
|
name: "search",
|
|
@@ -128,12 +158,62 @@ cli({
|
|
|
128
158
|
if (!id)
|
|
129
159
|
throw new Error("pmlr paper id is required.");
|
|
130
160
|
const volume = requireVolume(kwargs.volume);
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
161
|
+
return [await findPmlrPaper(volume, id)];
|
|
162
|
+
},
|
|
163
|
+
});
|
|
164
|
+
cli({
|
|
165
|
+
site: "pmlr",
|
|
166
|
+
name: "read",
|
|
167
|
+
description: "Download a PMLR paper PDF by id inside a proceedings volume and extract text",
|
|
168
|
+
domain: "proceedings.mlr.press",
|
|
169
|
+
strategy: Strategy.PUBLIC,
|
|
170
|
+
args: [
|
|
171
|
+
{ name: "id", type: "str", required: true, positional: true },
|
|
172
|
+
{ name: "volume", type: "str", default: "235" },
|
|
173
|
+
{
|
|
174
|
+
name: "output",
|
|
175
|
+
type: "str",
|
|
176
|
+
default: "./pmlr-downloads",
|
|
177
|
+
description: "Output directory for the downloaded PDF",
|
|
178
|
+
"x-unicli-kind": "path",
|
|
179
|
+
},
|
|
180
|
+
{ name: "filename", type: "str", description: "Output PDF filename" },
|
|
181
|
+
{ name: "first-page", type: "int", default: 1, description: "First page" },
|
|
182
|
+
{ name: "last-page", type: "int", default: 20, description: "Last page" },
|
|
183
|
+
{
|
|
184
|
+
name: "max-chars",
|
|
185
|
+
type: "int",
|
|
186
|
+
default: 40000,
|
|
187
|
+
description: "Maximum extracted text characters",
|
|
188
|
+
},
|
|
189
|
+
],
|
|
190
|
+
columns: [
|
|
191
|
+
"id",
|
|
192
|
+
"title",
|
|
193
|
+
"source_adapter",
|
|
194
|
+
"source_url",
|
|
195
|
+
"pdf_url",
|
|
196
|
+
"path",
|
|
197
|
+
"text_source",
|
|
198
|
+
"text",
|
|
199
|
+
"text_chars",
|
|
200
|
+
"text_truncated",
|
|
201
|
+
],
|
|
202
|
+
capabilities: [
|
|
203
|
+
"http.fetch",
|
|
204
|
+
"http.download",
|
|
205
|
+
"subprocess.exec",
|
|
206
|
+
"scholar.fulltext",
|
|
207
|
+
"scholar.pdf",
|
|
208
|
+
],
|
|
209
|
+
executables: ["pdftotext"],
|
|
210
|
+
minimum_capability: "subprocess.exec",
|
|
211
|
+
func: async (_page, kwargs) => {
|
|
212
|
+
const id = String(kwargs.id ?? kwargs.ref ?? "").trim();
|
|
213
|
+
if (!id)
|
|
214
|
+
throw new Error("pmlr paper id is required.");
|
|
215
|
+
const volume = requireVolume(kwargs.volume);
|
|
216
|
+
return [await readPmlrPaperPdf(await findPmlrPaper(volume, id), kwargs)];
|
|
137
217
|
},
|
|
138
218
|
});
|
|
139
219
|
//# sourceMappingURL=proceedings.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"proceedings.js","sourceRoot":"","sources":["../../../src/adapters/pmlr/proceedings.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,IAAI,MAAM,SAAS,CAAC;AAC3B,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"proceedings.js","sourceRoot":"","sources":["../../../src/adapters/pmlr/proceedings.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @owner src/adapters/pubmed/articles.ts
|
|
3
|
-
* @does Register agent-facing PubMed search, article, author, citation, and related-article commands.
|
|
4
|
-
* @needs NCBI E-utilities
|
|
5
|
-
* @feeds surface coverage ledger, biomedical literature command surface, agent-readable PubMed rows.
|
|
6
|
-
* @breaks NCBI E-utilities envelope drift, weak PMID validation, or silent empty rows hide literature lookup failures.
|
|
3
|
+
* @does Register agent-facing PubMed search, normalized paper metadata, field/value article detail, PMC full-text read, author, citation, and related-article commands.
|
|
4
|
+
* @needs NCBI E-utilities PubMed/PMC APIs, TypeScript adapter loader, PMID/PMCID/query validation.
|
|
5
|
+
* @feeds surface coverage ledger, biomedical literature command surface, agent-readable PubMed rows, scholar full-text workflow.
|
|
6
|
+
* @breaks NCBI E-utilities envelope drift, weak PMID/PMCID validation, missing PMC full text, or silent empty rows hide literature lookup failures.
|
|
7
7
|
*/
|
|
8
8
|
interface PubMedSummary {
|
|
9
9
|
uid?: unknown;
|
|
@@ -24,8 +24,12 @@ interface PubMedSummary {
|
|
|
24
24
|
}
|
|
25
25
|
export declare function requirePubMedText(value: unknown, label: string): string;
|
|
26
26
|
export declare function requirePmid(value: unknown, label?: string): string;
|
|
27
|
+
export declare function normalizePmcId(value: unknown): string;
|
|
27
28
|
export declare function requirePubMedLimit(value: unknown, fallback?: number, max?: number): number;
|
|
29
|
+
export declare function requirePubMedMaxChars(value: unknown, fallback?: number): number;
|
|
28
30
|
export declare function mapPubMedSummaryRows(summaries: PubMedSummary[], pmids: string[]): Array<Record<string, unknown>>;
|
|
31
|
+
export declare function mapPubMedArticleRecord(xml: string, pmid: string): Record<string, unknown>;
|
|
29
32
|
export declare function mapPubMedArticleRows(xml: string, pmid: string, fullAbstract?: boolean): Array<Record<string, unknown>>;
|
|
33
|
+
export declare function mapPmcFullTextRow(xml: string, ref: string, maxChars?: number): Record<string, unknown>;
|
|
30
34
|
export {};
|
|
31
35
|
//# sourceMappingURL=articles.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"articles.d.ts","sourceRoot":"","sources":["../../../src/adapters/pubmed/articles.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;
|
|
1
|
+
{"version":3,"file":"articles.d.ts","sourceRoot":"","sources":["../../../src/adapters/pubmed/articles.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAkCH,UAAU,aAAa;IACrB,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,OAAO,CAAC,EAAE,KAAK,CAAC;QACd,IAAI,CAAC,EAAE,OAAO,CAAC;QACf,cAAc,CAAC,EAAE,OAAO,CAAC;QACzB,QAAQ,CAAC,EAAE,OAAO,CAAC;QACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;KACpB,CAAC,CAAC;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,EAAE,CAAC;IACpB,UAAU,CAAC,EAAE,KAAK,CAAC;QACjB,MAAM,CAAC,EAAE,OAAO,CAAC;QACjB,KAAK,CAAC,EAAE,OAAO,CAAC;KACjB,CAAC,CAAC;CACJ;AAkBD,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAIvE;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,SAAS,GAAG,MAAM,CAKlE;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAMrD;AAED,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,OAAO,EACd,QAAQ,SAAK,EACb,GAAG,SAAM,GACR,MAAM,CASR;AAED,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,OAAO,EACd,QAAQ,SAAS,GAChB,MAAM,CASR;AAsGD,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,aAAa,EAAE,EAC1B,KAAK,EAAE,MAAM,EAAE,GACd,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CA4BhC;AA2CD,wBAAgB,sBAAsB,CACpC,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,GACX,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CA4CzB;AAED,wBAAgB,oBAAoB,CAClC,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,EACZ,YAAY,UAAQ,GACnB,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAsBhC;AA4CD,wBAAgB,iBAAiB,CAC/B,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,EACX,QAAQ,SAAS,GAChB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAyCzB"}
|
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @owner src/adapters/pubmed/articles.ts
|
|
3
|
-
* @does Register agent-facing PubMed search, article, author, citation, and related-article commands.
|
|
4
|
-
* @needs NCBI E-utilities
|
|
5
|
-
* @feeds surface coverage ledger, biomedical literature command surface, agent-readable PubMed rows.
|
|
6
|
-
* @breaks NCBI E-utilities envelope drift, weak PMID validation, or silent empty rows hide literature lookup failures.
|
|
3
|
+
* @does Register agent-facing PubMed search, normalized paper metadata, field/value article detail, PMC full-text read, author, citation, and related-article commands.
|
|
4
|
+
* @needs NCBI E-utilities PubMed/PMC APIs, TypeScript adapter loader, PMID/PMCID/query validation.
|
|
5
|
+
* @feeds surface coverage ledger, biomedical literature command surface, agent-readable PubMed rows, scholar full-text workflow.
|
|
6
|
+
* @breaks NCBI E-utilities envelope drift, weak PMID/PMCID validation, missing PMC full text, or silent empty rows hide literature lookup failures.
|
|
7
7
|
*/
|
|
8
8
|
import { DOMParser } from "@xmldom/xmldom";
|
|
9
9
|
import { cli, Strategy } from "../../registry.js";
|
|
10
10
|
const EUTILS_BASE = "https://eutils.ncbi.nlm.nih.gov/entrez/eutils";
|
|
11
11
|
const SUMMARY_COLUMNS = [
|
|
12
12
|
"rank",
|
|
13
|
+
"id",
|
|
13
14
|
"pmid",
|
|
14
15
|
"title",
|
|
15
16
|
"authors",
|
|
@@ -17,9 +18,23 @@ const SUMMARY_COLUMNS = [
|
|
|
17
18
|
"year",
|
|
18
19
|
"article_type",
|
|
19
20
|
"doi",
|
|
21
|
+
"pmc_id",
|
|
20
22
|
"url",
|
|
21
23
|
];
|
|
22
|
-
const RELATED_COLUMNS = [
|
|
24
|
+
const RELATED_COLUMNS = [
|
|
25
|
+
"rank",
|
|
26
|
+
"id",
|
|
27
|
+
"pmid",
|
|
28
|
+
"title",
|
|
29
|
+
"authors",
|
|
30
|
+
"journal",
|
|
31
|
+
"year",
|
|
32
|
+
"score",
|
|
33
|
+
"doi",
|
|
34
|
+
"pmc_id",
|
|
35
|
+
"url",
|
|
36
|
+
];
|
|
37
|
+
const PMC_BASE = "https://pmc.ncbi.nlm.nih.gov/articles";
|
|
23
38
|
function stringField(value) {
|
|
24
39
|
return typeof value === "string" ? value : "";
|
|
25
40
|
}
|
|
@@ -46,6 +61,15 @@ export function requirePmid(value, label = "pmid") {
|
|
|
46
61
|
throw new Error(`pubmed ${label} must be a numeric PMID.`);
|
|
47
62
|
return pmid;
|
|
48
63
|
}
|
|
64
|
+
export function normalizePmcId(value) {
|
|
65
|
+
const raw = String(value ?? "").trim();
|
|
66
|
+
if (!raw)
|
|
67
|
+
return "";
|
|
68
|
+
const match = raw.match(/^(?:PMC)?(\d+)$/i);
|
|
69
|
+
if (!match)
|
|
70
|
+
throw new Error(`pubmed pmc id "${raw}" is not valid.`);
|
|
71
|
+
return `PMC${match[1]}`;
|
|
72
|
+
}
|
|
49
73
|
export function requirePubMedLimit(value, fallback = 20, max = 100) {
|
|
50
74
|
if (value === undefined || value === null || value === "")
|
|
51
75
|
return fallback;
|
|
@@ -55,6 +79,15 @@ export function requirePubMedLimit(value, fallback = 20, max = 100) {
|
|
|
55
79
|
}
|
|
56
80
|
return n;
|
|
57
81
|
}
|
|
82
|
+
export function requirePubMedMaxChars(value, fallback = 40_000) {
|
|
83
|
+
if (value === undefined || value === null || value === "")
|
|
84
|
+
return fallback;
|
|
85
|
+
const n = Number(value);
|
|
86
|
+
if (!Number.isInteger(n) || n < 1_000 || n > 1_000_000) {
|
|
87
|
+
throw new Error(`pubmed max-chars must be an integer in [1000, 1000000]. Got: ${String(value)}`);
|
|
88
|
+
}
|
|
89
|
+
return n;
|
|
90
|
+
}
|
|
58
91
|
function requireChoice(value, choices, label, fallback) {
|
|
59
92
|
const text = String(value ?? fallback).trim();
|
|
60
93
|
if (!choices.includes(text))
|
|
@@ -64,9 +97,9 @@ function requireChoice(value, choices, label, fallback) {
|
|
|
64
97
|
function year(value) {
|
|
65
98
|
return stringField(value).match(/\d{4}/)?.[0] ?? "";
|
|
66
99
|
}
|
|
67
|
-
function buildUrl(tool, params, retmode = "json") {
|
|
100
|
+
function buildUrl(tool, params, retmode = "json", db = "pubmed") {
|
|
68
101
|
const search = new URLSearchParams();
|
|
69
|
-
search.set("db",
|
|
102
|
+
search.set("db", db);
|
|
70
103
|
search.set("retmode", retmode);
|
|
71
104
|
if (process.env.NCBI_API_KEY)
|
|
72
105
|
search.set("api_key", process.env.NCBI_API_KEY);
|
|
@@ -78,8 +111,8 @@ function buildUrl(tool, params, retmode = "json") {
|
|
|
78
111
|
}
|
|
79
112
|
return `${EUTILS_BASE}/${tool}.fcgi?${search.toString()}`;
|
|
80
113
|
}
|
|
81
|
-
async function eutilsFetch(tool, params, retmode = "json") {
|
|
82
|
-
const response = await fetch(buildUrl(tool, params, retmode), {
|
|
114
|
+
async function eutilsFetch(tool, params, retmode = "json", db = "pubmed") {
|
|
115
|
+
const response = await fetch(buildUrl(tool, params, retmode, db), {
|
|
83
116
|
headers: { "User-Agent": "unicli (https://github.com/olo-dot-io/Uni-CLI)" },
|
|
84
117
|
});
|
|
85
118
|
if (!response.ok)
|
|
@@ -108,11 +141,16 @@ function authorNames(authors, max = 3) {
|
|
|
108
141
|
return shown.join(", ");
|
|
109
142
|
}
|
|
110
143
|
function doi(articleIds) {
|
|
144
|
+
return articleId(articleIds, "doi");
|
|
145
|
+
}
|
|
146
|
+
function articleId(articleIds, type) {
|
|
111
147
|
return stringField(Array.isArray(articleIds)
|
|
112
|
-
? articleIds.find((id) => stringField(id.idtype).toLowerCase() ===
|
|
113
|
-
?.value
|
|
148
|
+
? articleIds.find((id) => stringField(id.idtype).toLowerCase() === type.toLowerCase())?.value
|
|
114
149
|
: "");
|
|
115
150
|
}
|
|
151
|
+
function pmcUrl(pmcId) {
|
|
152
|
+
return pmcId ? `${PMC_BASE}/${pmcId}/` : "";
|
|
153
|
+
}
|
|
116
154
|
function articleType(types) {
|
|
117
155
|
const values = Array.isArray(types)
|
|
118
156
|
? types.map(stringField).filter(Boolean)
|
|
@@ -124,17 +162,27 @@ export function mapPubMedSummaryRows(summaries, pmids) {
|
|
|
124
162
|
const summary = summaries.find((item) => stringField(item.uid) === pmid);
|
|
125
163
|
if (!summary)
|
|
126
164
|
return [];
|
|
165
|
+
const pmcId = articleId(summary.articleids, "pmc");
|
|
166
|
+
const url = `https://pubmed.ncbi.nlm.nih.gov/${pmid}/`;
|
|
127
167
|
return [
|
|
128
168
|
{
|
|
129
169
|
rank: index + 1,
|
|
170
|
+
id: pmid,
|
|
130
171
|
pmid,
|
|
131
172
|
title: cleanText(summary.title),
|
|
132
173
|
authors: authorNames(summary.authors),
|
|
133
174
|
journal: stringField(summary.source),
|
|
175
|
+
venue: stringField(summary.source),
|
|
134
176
|
year: year(summary.pubdate),
|
|
135
177
|
article_type: articleType(summary.pubtype ?? []),
|
|
178
|
+
type: articleType(summary.pubtype ?? []),
|
|
136
179
|
doi: doi(summary.articleids),
|
|
137
|
-
|
|
180
|
+
pmc_id: pmcId || undefined,
|
|
181
|
+
pmc_url: pmcUrl(pmcId),
|
|
182
|
+
source_adapter: "pubmed",
|
|
183
|
+
source_url: url,
|
|
184
|
+
retrieved_at: new Date().toISOString(),
|
|
185
|
+
url,
|
|
138
186
|
},
|
|
139
187
|
];
|
|
140
188
|
});
|
|
@@ -151,49 +199,162 @@ function elementTexts(root, tagName) {
|
|
|
151
199
|
function firstElement(root, tagName) {
|
|
152
200
|
return root.getElementsByTagName(tagName)[0] ?? null;
|
|
153
201
|
}
|
|
154
|
-
|
|
202
|
+
function elements(root, tagName) {
|
|
203
|
+
const nodes = root.getElementsByTagName(tagName);
|
|
204
|
+
return Array.from({ length: nodes.length }, (_, index) => nodes.item(index)).filter((node) => node !== null);
|
|
205
|
+
}
|
|
206
|
+
function articleIdText(root, attrName, attrValue) {
|
|
207
|
+
return (elements(root, attrName === "IdType" ? "ArticleId" : "article-id")
|
|
208
|
+
.find((node) => node.getAttribute(attrName)?.toLowerCase() ===
|
|
209
|
+
attrValue.toLowerCase())
|
|
210
|
+
?.textContent?.trim() ?? "");
|
|
211
|
+
}
|
|
212
|
+
export function mapPubMedArticleRecord(xml, pmid) {
|
|
155
213
|
const document = new DOMParser().parseFromString(xml, "text/xml");
|
|
156
214
|
const title = childText(document, "ArticleTitle");
|
|
157
215
|
if (!title)
|
|
158
216
|
throw new Error(`pubmed article ${pmid} did not include a title.`);
|
|
217
|
+
const doiValue = articleIdText(document, "IdType", "doi");
|
|
218
|
+
const pmcId = articleIdText(document, "IdType", "pmc");
|
|
159
219
|
const abstract = elementTexts(document, "AbstractText").join(" ");
|
|
160
|
-
const shownAbstract = fullAbstract || abstract.length <= 500
|
|
161
|
-
? abstract
|
|
162
|
-
: `${abstract.slice(0, 497)}...`;
|
|
163
|
-
const doiValue = Array.from({ length: document.getElementsByTagName("ArticleId").length }, (_, index) => document.getElementsByTagName("ArticleId").item(index))
|
|
164
|
-
.filter((node) => node !== null)
|
|
165
|
-
.find((node) => node.getAttribute("IdType")?.toLowerCase() === "doi")
|
|
166
|
-
?.textContent?.trim() ?? "";
|
|
167
220
|
const authorNodes = document.getElementsByTagName("Author");
|
|
168
|
-
const
|
|
221
|
+
const authorList = Array.from({ length: authorNodes.length }, (_, index) => authorNodes.item(index))
|
|
169
222
|
.filter((author) => author !== null)
|
|
170
223
|
.map((author) => [childText(author, "LastName"), childText(author, "Initials")]
|
|
171
224
|
.filter(Boolean)
|
|
172
225
|
.join(" "))
|
|
173
|
-
.filter(Boolean)
|
|
174
|
-
.join(", ");
|
|
226
|
+
.filter(Boolean);
|
|
175
227
|
const journal = firstElement(document, "Journal");
|
|
176
228
|
const pubDate = firstElement(document, "PubDate");
|
|
229
|
+
const yearValue = pubDate ? childText(pubDate, "Year") : "";
|
|
230
|
+
const sourceUrl = `https://pubmed.ncbi.nlm.nih.gov/${pmid}/`;
|
|
231
|
+
return {
|
|
232
|
+
id: pmid,
|
|
233
|
+
pmid,
|
|
234
|
+
title,
|
|
235
|
+
authors: authorList,
|
|
236
|
+
journal: journal ? childText(journal, "Title") : "",
|
|
237
|
+
venue: journal ? childText(journal, "Title") : "",
|
|
238
|
+
year: yearValue ? Number(yearValue) : undefined,
|
|
239
|
+
date: pubDate ? cleanText(pubDate.textContent ?? "") : "",
|
|
240
|
+
article_type: elementTexts(document, "PublicationType")[0] ?? "",
|
|
241
|
+
type: elementTexts(document, "PublicationType")[0] ?? "",
|
|
242
|
+
language: childText(document, "Language"),
|
|
243
|
+
doi: doiValue || undefined,
|
|
244
|
+
pmc_id: pmcId || undefined,
|
|
245
|
+
pmc_url: pmcUrl(pmcId),
|
|
246
|
+
abstract: abstract || undefined,
|
|
247
|
+
source_adapter: "pubmed",
|
|
248
|
+
source_url: sourceUrl,
|
|
249
|
+
retrieved_at: new Date().toISOString(),
|
|
250
|
+
url: sourceUrl,
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
export function mapPubMedArticleRows(xml, pmid, fullAbstract = false) {
|
|
254
|
+
const record = mapPubMedArticleRecord(xml, pmid);
|
|
255
|
+
const abstract = stringField(record.abstract);
|
|
256
|
+
const shownAbstract = fullAbstract || abstract.length <= 500
|
|
257
|
+
? abstract
|
|
258
|
+
: `${abstract.slice(0, 497)}...`;
|
|
177
259
|
return [
|
|
178
260
|
{ field: "PMID", value: pmid },
|
|
179
|
-
{ field: "
|
|
180
|
-
{ field: "
|
|
181
|
-
{ field: "
|
|
182
|
-
{ field: "
|
|
183
|
-
{
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
},
|
|
187
|
-
{
|
|
188
|
-
field: "Article Type",
|
|
189
|
-
value: elementTexts(document, "PublicationType")[0] ?? null,
|
|
190
|
-
},
|
|
191
|
-
{ field: "Language", value: childText(document, "Language") },
|
|
192
|
-
{ field: "DOI", value: doiValue || null },
|
|
261
|
+
{ field: "PMCID", value: record.pmc_id || null },
|
|
262
|
+
{ field: "Title", value: record.title },
|
|
263
|
+
{ field: "Authors", value: record.authors.join(", ") },
|
|
264
|
+
{ field: "Journal", value: record.journal },
|
|
265
|
+
{ field: "Year", value: record.year ? String(record.year) : "" },
|
|
266
|
+
{ field: "Date", value: record.date },
|
|
267
|
+
{ field: "Article Type", value: record.article_type || null },
|
|
268
|
+
{ field: "Language", value: record.language },
|
|
269
|
+
{ field: "DOI", value: record.doi || null },
|
|
193
270
|
{ field: "Abstract", value: shownAbstract || null },
|
|
194
|
-
{ field: "URL", value:
|
|
271
|
+
{ field: "URL", value: record.source_url },
|
|
272
|
+
{ field: "PMC URL", value: record.pmc_url || null },
|
|
195
273
|
];
|
|
196
274
|
}
|
|
275
|
+
function directChildElements(root, tagName) {
|
|
276
|
+
const out = [];
|
|
277
|
+
for (let index = 0; index < root.childNodes.length; index += 1) {
|
|
278
|
+
const node = root.childNodes.item(index);
|
|
279
|
+
if (node?.nodeType === 1 && node.nodeName === tagName) {
|
|
280
|
+
out.push(node);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
return out;
|
|
284
|
+
}
|
|
285
|
+
function directChildText(root, tagName) {
|
|
286
|
+
return cleanText(directChildElements(root, tagName)[0]?.textContent ?? "");
|
|
287
|
+
}
|
|
288
|
+
function sectionText(section) {
|
|
289
|
+
const title = directChildText(section, "title");
|
|
290
|
+
const paragraphs = directChildElements(section, "p")
|
|
291
|
+
.map((paragraph) => cleanText(paragraph.textContent ?? ""))
|
|
292
|
+
.filter(Boolean);
|
|
293
|
+
const nested = directChildElements(section, "sec")
|
|
294
|
+
.map(sectionText)
|
|
295
|
+
.filter(Boolean);
|
|
296
|
+
return [title ? `## ${title}` : "", ...paragraphs, ...nested]
|
|
297
|
+
.filter(Boolean)
|
|
298
|
+
.join("\n\n");
|
|
299
|
+
}
|
|
300
|
+
function truncateText(text, maxChars) {
|
|
301
|
+
if (text.length <= maxChars)
|
|
302
|
+
return { text, truncated: false };
|
|
303
|
+
return {
|
|
304
|
+
text: `${text.slice(0, maxChars).trimEnd()}\n\n[truncated at ${maxChars} characters]`,
|
|
305
|
+
truncated: true,
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
export function mapPmcFullTextRow(xml, ref, maxChars = 40_000) {
|
|
309
|
+
const document = new DOMParser().parseFromString(xml, "text/xml");
|
|
310
|
+
const title = childText(document, "article-title");
|
|
311
|
+
if (!title) {
|
|
312
|
+
throw new Error(`PMC full text ${ref} did not include an article title.`);
|
|
313
|
+
}
|
|
314
|
+
const pmcId = normalizePmcId(articleIdText(document, "pub-id-type", "pmcid") || ref);
|
|
315
|
+
const pmid = articleIdText(document, "pub-id-type", "pmid");
|
|
316
|
+
const doiValue = articleIdText(document, "pub-id-type", "doi");
|
|
317
|
+
const abstract = cleanText(firstElement(document, "abstract")?.textContent ?? "");
|
|
318
|
+
const body = firstElement(document, "body");
|
|
319
|
+
const bodyText = body
|
|
320
|
+
? directChildElements(body, "sec")
|
|
321
|
+
.map(sectionText)
|
|
322
|
+
.filter(Boolean)
|
|
323
|
+
.join("\n\n")
|
|
324
|
+
: "";
|
|
325
|
+
const text = [abstract ? `## Abstract\n\n${abstract}` : "", bodyText]
|
|
326
|
+
.filter(Boolean)
|
|
327
|
+
.join("\n\n");
|
|
328
|
+
if (!text) {
|
|
329
|
+
throw new Error(`PMC full text ${pmcId} did not include readable text.`);
|
|
330
|
+
}
|
|
331
|
+
const truncated = truncateText(text, maxChars);
|
|
332
|
+
return {
|
|
333
|
+
id: pmid || pmcId,
|
|
334
|
+
title,
|
|
335
|
+
pmid: pmid || undefined,
|
|
336
|
+
pmc_id: pmcId,
|
|
337
|
+
doi: doiValue || undefined,
|
|
338
|
+
source_adapter: "pubmed",
|
|
339
|
+
source_url: pmcUrl(pmcId),
|
|
340
|
+
text: truncated.text,
|
|
341
|
+
text_truncated: truncated.truncated,
|
|
342
|
+
text_source: "pmc_xml",
|
|
343
|
+
retrieved_at: new Date().toISOString(),
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
async function pmcIdFromPubMedRef(ref) {
|
|
347
|
+
if (/^(?:PMC)?\d+$/i.test(ref) && /^PMC/i.test(ref)) {
|
|
348
|
+
return normalizePmcId(ref);
|
|
349
|
+
}
|
|
350
|
+
const pmid = requirePmid(ref, "pmid");
|
|
351
|
+
const json = (await eutilsFetch("esearch", { term: `${pmid}[PMID]`, retmax: 1 }, "json", "pmc"));
|
|
352
|
+
const numericPmc = json.esearchresult?.idlist?.[0];
|
|
353
|
+
if (!numericPmc) {
|
|
354
|
+
throw new Error(`PubMed PMID ${pmid} has no PubMed Central full text record.`);
|
|
355
|
+
}
|
|
356
|
+
return normalizePmcId(numericPmc);
|
|
357
|
+
}
|
|
197
358
|
async function fetchSummaryRows(pmids, label) {
|
|
198
359
|
const json = (await eutilsFetch("esummary", { id: pmids.join(",") }));
|
|
199
360
|
const result = json.result ?? {};
|
|
@@ -261,13 +422,85 @@ cli({
|
|
|
261
422
|
},
|
|
262
423
|
],
|
|
263
424
|
columns: ["field", "value"],
|
|
264
|
-
capabilities: ["http.fetch"
|
|
425
|
+
capabilities: ["http.fetch"],
|
|
265
426
|
func: async (_page, kwargs) => {
|
|
266
427
|
const pmid = requirePmid(kwargs.pmid);
|
|
267
428
|
const xml = String(await eutilsFetch("efetch", { id: pmid, rettype: "abstract" }, "xml"));
|
|
268
429
|
return mapPubMedArticleRows(xml, pmid, kwargs["full-abstract"] === true);
|
|
269
430
|
},
|
|
270
431
|
});
|
|
432
|
+
cli({
|
|
433
|
+
site: "pubmed",
|
|
434
|
+
name: "paper",
|
|
435
|
+
description: "Fetch normalized PubMed article metadata by PMID",
|
|
436
|
+
domain: "pubmed.ncbi.nlm.nih.gov",
|
|
437
|
+
strategy: Strategy.PUBLIC,
|
|
438
|
+
args: [
|
|
439
|
+
{
|
|
440
|
+
name: "pmid",
|
|
441
|
+
type: "str",
|
|
442
|
+
required: true,
|
|
443
|
+
positional: true,
|
|
444
|
+
description: "PubMed ID",
|
|
445
|
+
},
|
|
446
|
+
],
|
|
447
|
+
columns: [
|
|
448
|
+
"id",
|
|
449
|
+
"title",
|
|
450
|
+
"authors",
|
|
451
|
+
"year",
|
|
452
|
+
"journal",
|
|
453
|
+
"doi",
|
|
454
|
+
"pmc_id",
|
|
455
|
+
"source_url",
|
|
456
|
+
],
|
|
457
|
+
capabilities: ["http.fetch", "scholar.get"],
|
|
458
|
+
func: async (_page, kwargs) => {
|
|
459
|
+
const pmid = requirePmid(kwargs.pmid ?? kwargs.id ?? kwargs.ref);
|
|
460
|
+
const xml = String(await eutilsFetch("efetch", { id: pmid, rettype: "abstract" }, "xml"));
|
|
461
|
+
return [mapPubMedArticleRecord(xml, pmid)];
|
|
462
|
+
},
|
|
463
|
+
});
|
|
464
|
+
cli({
|
|
465
|
+
site: "pubmed",
|
|
466
|
+
name: "read",
|
|
467
|
+
description: "Read PubMed Central full text for a PMID or PMCID",
|
|
468
|
+
domain: "eutils.ncbi.nlm.nih.gov",
|
|
469
|
+
strategy: Strategy.PUBLIC,
|
|
470
|
+
args: [
|
|
471
|
+
{
|
|
472
|
+
name: "ref",
|
|
473
|
+
type: "str",
|
|
474
|
+
required: true,
|
|
475
|
+
positional: true,
|
|
476
|
+
description: "PubMed PMID or PubMed Central PMCID",
|
|
477
|
+
},
|
|
478
|
+
{
|
|
479
|
+
name: "max-chars",
|
|
480
|
+
type: "int",
|
|
481
|
+
default: 40000,
|
|
482
|
+
description: "Maximum extracted text characters",
|
|
483
|
+
},
|
|
484
|
+
],
|
|
485
|
+
columns: [
|
|
486
|
+
"id",
|
|
487
|
+
"title",
|
|
488
|
+
"pmid",
|
|
489
|
+
"pmc_id",
|
|
490
|
+
"doi",
|
|
491
|
+
"source_url",
|
|
492
|
+
"text",
|
|
493
|
+
"text_truncated",
|
|
494
|
+
],
|
|
495
|
+
capabilities: ["http.fetch", "scholar.fulltext"],
|
|
496
|
+
func: async (_page, kwargs) => {
|
|
497
|
+
const ref = requirePubMedText(kwargs.ref ?? kwargs.id ?? kwargs.pmid, "ref");
|
|
498
|
+
const maxChars = requirePubMedMaxChars(kwargs["max-chars"]);
|
|
499
|
+
const pmcId = await pmcIdFromPubMedRef(ref);
|
|
500
|
+
const xml = String(await eutilsFetch("efetch", { id: pmcId.replace(/^PMC/i, "") }, "xml", "pmc"));
|
|
501
|
+
return [mapPmcFullTextRow(xml, pmcId, maxChars)];
|
|
502
|
+
},
|
|
503
|
+
});
|
|
271
504
|
cli({
|
|
272
505
|
site: "pubmed",
|
|
273
506
|
name: "author",
|