@pharmatools/pubcrawl 2.0.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/LICENSE +21 -0
- package/README.md +111 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +45 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/cache.d.ts +19 -0
- package/dist/lib/cache.d.ts.map +1 -0
- package/dist/lib/cache.js +52 -0
- package/dist/lib/cache.js.map +1 -0
- package/dist/lib/dailymed.d.ts +9 -0
- package/dist/lib/dailymed.d.ts.map +1 -0
- package/dist/lib/dailymed.js +58 -0
- package/dist/lib/dailymed.js.map +1 -0
- package/dist/lib/emc.d.ts +13 -0
- package/dist/lib/emc.d.ts.map +1 -0
- package/dist/lib/emc.js +215 -0
- package/dist/lib/emc.js.map +1 -0
- package/dist/lib/label-mapping.d.ts +8 -0
- package/dist/lib/label-mapping.d.ts.map +1 -0
- package/dist/lib/label-mapping.js +23 -0
- package/dist/lib/label-mapping.js.map +1 -0
- package/dist/lib/ncbi.d.ts +37 -0
- package/dist/lib/ncbi.d.ts.map +1 -0
- package/dist/lib/ncbi.js +175 -0
- package/dist/lib/ncbi.js.map +1 -0
- package/dist/lib/openfda.d.ts +8 -0
- package/dist/lib/openfda.d.ts.map +1 -0
- package/dist/lib/openfda.js +83 -0
- package/dist/lib/openfda.js.map +1 -0
- package/dist/lib/xml-parser.d.ts +23 -0
- package/dist/lib/xml-parser.d.ts.map +1 -0
- package/dist/lib/xml-parser.js +273 -0
- package/dist/lib/xml-parser.js.map +1 -0
- package/dist/tools/abstract.d.ts +3 -0
- package/dist/tools/abstract.d.ts.map +1 -0
- package/dist/tools/abstract.js +107 -0
- package/dist/tools/abstract.js.map +1 -0
- package/dist/tools/cite.d.ts +3 -0
- package/dist/tools/cite.d.ts.map +1 -0
- package/dist/tools/cite.js +188 -0
- package/dist/tools/cite.js.map +1 -0
- package/dist/tools/compare-labels.d.ts +3 -0
- package/dist/tools/compare-labels.d.ts.map +1 -0
- package/dist/tools/compare-labels.js +126 -0
- package/dist/tools/compare-labels.js.map +1 -0
- package/dist/tools/fulltext.d.ts +3 -0
- package/dist/tools/fulltext.d.ts.map +1 -0
- package/dist/tools/fulltext.js +88 -0
- package/dist/tools/fulltext.js.map +1 -0
- package/dist/tools/related.d.ts +3 -0
- package/dist/tools/related.d.ts.map +1 -0
- package/dist/tools/related.js +63 -0
- package/dist/tools/related.js.map +1 -0
- package/dist/tools/search-indication.d.ts +3 -0
- package/dist/tools/search-indication.d.ts.map +1 -0
- package/dist/tools/search-indication.js +73 -0
- package/dist/tools/search-indication.js.map +1 -0
- package/dist/tools/search.d.ts +3 -0
- package/dist/tools/search.d.ts.map +1 -0
- package/dist/tools/search.js +69 -0
- package/dist/tools/search.js.map +1 -0
- package/dist/tools/smpc.d.ts +3 -0
- package/dist/tools/smpc.d.ts.map +1 -0
- package/dist/tools/smpc.js +52 -0
- package/dist/tools/smpc.js.map +1 -0
- package/dist/tools/trending.d.ts +3 -0
- package/dist/tools/trending.d.ts.map +1 -0
- package/dist/tools/trending.js +106 -0
- package/dist/tools/trending.js.map +1 -0
- package/dist/tools/uspi.d.ts +3 -0
- package/dist/tools/uspi.d.ts.map +1 -0
- package/dist/tools/uspi.js +117 -0
- package/dist/tools/uspi.js.map +1 -0
- package/dist/types.d.ts +93 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +49 -0
- package/server.json +29 -0
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { efetch } from "../lib/ncbi.js";
|
|
3
|
+
import { parseXml, parseAuthors, parseAbstractSections, parseMeshTerms, parseKeywords, extractText, } from "../lib/xml-parser.js";
|
|
4
|
+
const schema = {
|
|
5
|
+
pmid: z.string().describe("PubMed ID"),
|
|
6
|
+
structured: z.boolean().default(true).describe("Return structured abstract sections"),
|
|
7
|
+
};
|
|
8
|
+
export function registerAbstractTool(server) {
|
|
9
|
+
server.tool("get_abstract", "Get the full structured abstract and metadata for a PubMed article. Returns abstract sections (background, methods, results, conclusions), keywords, MeSH terms, and PMC ID.", schema, async (params) => {
|
|
10
|
+
try {
|
|
11
|
+
const xml = await efetch({ id: params.pmid, rettype: "xml" });
|
|
12
|
+
const parsed = parseXml(xml);
|
|
13
|
+
const articles = parsed.PubmedArticleSet?.PubmedArticle;
|
|
14
|
+
if (!articles || (Array.isArray(articles) && articles.length === 0)) {
|
|
15
|
+
return {
|
|
16
|
+
content: [{ type: "text", text: `No article found for PMID ${params.pmid}` }],
|
|
17
|
+
isError: true,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
const article = Array.isArray(articles) ? articles[0] : articles;
|
|
21
|
+
const medlineCitation = article.MedlineCitation;
|
|
22
|
+
const articleData = medlineCitation?.Article;
|
|
23
|
+
const pubmedData = article.PubmedData;
|
|
24
|
+
if (!articleData) {
|
|
25
|
+
return {
|
|
26
|
+
content: [{ type: "text", text: `No article data found for PMID ${params.pmid}` }],
|
|
27
|
+
isError: true,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
// Extract authors
|
|
31
|
+
const authors = parseAuthors(articleData.AuthorList);
|
|
32
|
+
// Extract journal info
|
|
33
|
+
const journal = articleData.Journal;
|
|
34
|
+
const journalTitle = extractText(journal?.Title);
|
|
35
|
+
const journalIssue = journal?.JournalIssue;
|
|
36
|
+
const volume = journalIssue?.Volume ? String(journalIssue.Volume) : "";
|
|
37
|
+
const issue = journalIssue?.Issue ? String(journalIssue.Issue) : "";
|
|
38
|
+
const year = journalIssue?.PubDate?.Year
|
|
39
|
+
? String(journalIssue.PubDate.Year)
|
|
40
|
+
: extractText(journalIssue?.PubDate?.MedlineDate).match(/\d{4}/)?.[0] ?? "";
|
|
41
|
+
const pages = articleData.Pagination?.MedlinePgn
|
|
42
|
+
? String(articleData.Pagination.MedlinePgn)
|
|
43
|
+
: "";
|
|
44
|
+
// Extract abstract
|
|
45
|
+
const abstractSections = parseAbstractSections(articleData.Abstract);
|
|
46
|
+
// If not structured, join all sections
|
|
47
|
+
let finalSections = abstractSections;
|
|
48
|
+
if (!params.structured && abstractSections.length > 0) {
|
|
49
|
+
const fullText = abstractSections.map((s) => s.text).join(" ");
|
|
50
|
+
finalSections = [{ label: "", text: fullText }];
|
|
51
|
+
}
|
|
52
|
+
// Extract DOI
|
|
53
|
+
let doi = "";
|
|
54
|
+
const elocationIds = articleData.ELocationID;
|
|
55
|
+
if (elocationIds) {
|
|
56
|
+
const ids = Array.isArray(elocationIds) ? elocationIds : [elocationIds];
|
|
57
|
+
for (const eid of ids) {
|
|
58
|
+
if (typeof eid === "object" && eid["@_EIdType"] === "doi") {
|
|
59
|
+
doi = extractText(eid);
|
|
60
|
+
break;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
// Extract PMC ID from article IDs
|
|
65
|
+
let pmcId = "";
|
|
66
|
+
const articleIdList = pubmedData?.ArticleIdList?.ArticleId;
|
|
67
|
+
if (articleIdList) {
|
|
68
|
+
const ids = Array.isArray(articleIdList) ? articleIdList : [articleIdList];
|
|
69
|
+
for (const id of ids) {
|
|
70
|
+
if (typeof id === "object" && id["@_IdType"] === "pmc") {
|
|
71
|
+
pmcId = extractText(id);
|
|
72
|
+
break;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
// Extract MeSH terms and keywords
|
|
77
|
+
const meshTerms = parseMeshTerms(medlineCitation?.MeshHeadingList);
|
|
78
|
+
const keywords = parseKeywords(medlineCitation?.KeywordList);
|
|
79
|
+
const result = {
|
|
80
|
+
pmid: params.pmid,
|
|
81
|
+
title: extractText(articleData.ArticleTitle),
|
|
82
|
+
authors,
|
|
83
|
+
journal: journalTitle,
|
|
84
|
+
year,
|
|
85
|
+
doi,
|
|
86
|
+
volume,
|
|
87
|
+
issue,
|
|
88
|
+
pages,
|
|
89
|
+
abstract_sections: finalSections,
|
|
90
|
+
keywords,
|
|
91
|
+
mesh_terms: meshTerms,
|
|
92
|
+
pmc_id: pmcId,
|
|
93
|
+
};
|
|
94
|
+
return {
|
|
95
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
100
|
+
return {
|
|
101
|
+
content: [{ type: "text", text: `Error fetching abstract: ${message}` }],
|
|
102
|
+
isError: true,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
//# sourceMappingURL=abstract.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"abstract.js","sourceRoot":"","sources":["../../src/tools/abstract.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cite.d.ts","sourceRoot":"","sources":["../../src/tools/cite.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AA4IpE,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAmFxD"}
|
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { efetch } from "../lib/ncbi.js";
|
|
3
|
+
import { parseXml, parseAuthors, extractText } from "../lib/xml-parser.js";
|
|
4
|
+
const schema = {
|
|
5
|
+
pmid: z.string().describe("PubMed ID"),
|
|
6
|
+
style: z.enum(["apa", "vancouver", "harvard", "bibtex"]).default("apa").describe("Citation style"),
|
|
7
|
+
};
|
|
8
|
+
function formatApa(info) {
|
|
9
|
+
const authorStr = info.authors.length === 0
|
|
10
|
+
? ""
|
|
11
|
+
: info.authors.length <= 7
|
|
12
|
+
? info.authors.map((a) => {
|
|
13
|
+
const parts = a.split(" ");
|
|
14
|
+
const last = parts[0];
|
|
15
|
+
const initials = parts.slice(1).map((p) => p[0] + ".").join(" ");
|
|
16
|
+
return `${last}, ${initials}`;
|
|
17
|
+
}).join(", ")
|
|
18
|
+
: info.authors.slice(0, 6).map((a) => {
|
|
19
|
+
const parts = a.split(" ");
|
|
20
|
+
const last = parts[0];
|
|
21
|
+
const initials = parts.slice(1).map((p) => p[0] + ".").join(" ");
|
|
22
|
+
return `${last}, ${initials}`;
|
|
23
|
+
}).join(", ") + ", ... " + (() => {
|
|
24
|
+
const last = info.authors[info.authors.length - 1];
|
|
25
|
+
const parts = last.split(" ");
|
|
26
|
+
const lastName = parts[0];
|
|
27
|
+
const initials = parts.slice(1).map((p) => p[0] + ".").join(" ");
|
|
28
|
+
return `${lastName}, ${initials}`;
|
|
29
|
+
})();
|
|
30
|
+
const yearPart = info.year ? ` (${info.year}).` : ".";
|
|
31
|
+
const titlePart = info.title.endsWith(".") ? ` ${info.title}` : ` ${info.title}.`;
|
|
32
|
+
const journalPart = ` *${info.journal}*`;
|
|
33
|
+
const volPart = info.volume ? `, *${info.volume}*` : "";
|
|
34
|
+
const issuePart = info.issue ? `(${info.issue})` : "";
|
|
35
|
+
const pagesPart = info.pages ? `, ${info.pages}` : "";
|
|
36
|
+
const doiPart = info.doi ? ` https://doi.org/${info.doi}` : "";
|
|
37
|
+
return `${authorStr}${yearPart}${titlePart}${journalPart}${volPart}${issuePart}${pagesPart}.${doiPart}`.trim();
|
|
38
|
+
}
|
|
39
|
+
function formatVancouver(info) {
|
|
40
|
+
const authorStr = info.authors.length === 0
|
|
41
|
+
? ""
|
|
42
|
+
: info.authors.length <= 6
|
|
43
|
+
? info.authors.map((a) => {
|
|
44
|
+
const parts = a.split(" ");
|
|
45
|
+
const last = parts[0];
|
|
46
|
+
const initials = parts.slice(1).map((p) => p[0]).join("");
|
|
47
|
+
return `${last} ${initials}`;
|
|
48
|
+
}).join(", ")
|
|
49
|
+
: info.authors.slice(0, 6).map((a) => {
|
|
50
|
+
const parts = a.split(" ");
|
|
51
|
+
const last = parts[0];
|
|
52
|
+
const initials = parts.slice(1).map((p) => p[0]).join("");
|
|
53
|
+
return `${last} ${initials}`;
|
|
54
|
+
}).join(", ") + ", et al";
|
|
55
|
+
const titlePart = info.title.endsWith(".") ? ` ${info.title}` : ` ${info.title}.`;
|
|
56
|
+
const journalPart = ` ${info.journal}.`;
|
|
57
|
+
const yearPart = info.year ? ` ${info.year}` : "";
|
|
58
|
+
const volPart = info.volume ? `;${info.volume}` : "";
|
|
59
|
+
const issuePart = info.issue ? `(${info.issue})` : "";
|
|
60
|
+
const pagesPart = info.pages ? `:${info.pages}` : "";
|
|
61
|
+
const doiPart = info.doi ? ` doi:${info.doi}` : "";
|
|
62
|
+
return `${authorStr}.${titlePart}${journalPart}${yearPart}${volPart}${issuePart}${pagesPart}.${doiPart}`.trim();
|
|
63
|
+
}
|
|
64
|
+
function formatHarvard(info) {
|
|
65
|
+
const authorStr = info.authors.length === 0
|
|
66
|
+
? ""
|
|
67
|
+
: info.authors.length <= 3
|
|
68
|
+
? info.authors.map((a) => {
|
|
69
|
+
const parts = a.split(" ");
|
|
70
|
+
const last = parts[0];
|
|
71
|
+
const initials = parts.slice(1).map((p) => p[0] + ".").join("");
|
|
72
|
+
return `${last}, ${initials}`;
|
|
73
|
+
}).join(", ")
|
|
74
|
+
: (() => {
|
|
75
|
+
const first = info.authors[0];
|
|
76
|
+
const parts = first.split(" ");
|
|
77
|
+
const last = parts[0];
|
|
78
|
+
const initials = parts.slice(1).map((p) => p[0] + ".").join("");
|
|
79
|
+
return `${last}, ${initials} et al.`;
|
|
80
|
+
})();
|
|
81
|
+
const yearPart = info.year ? ` ${info.year}.` : ".";
|
|
82
|
+
const titlePart = ` '${info.title}'.`;
|
|
83
|
+
const journalPart = ` *${info.journal}*`;
|
|
84
|
+
const volPart = info.volume ? `, ${info.volume}` : "";
|
|
85
|
+
const issuePart = info.issue ? `(${info.issue})` : "";
|
|
86
|
+
const pagesPart = info.pages ? `, pp. ${info.pages}` : "";
|
|
87
|
+
const doiPart = info.doi ? `. doi:${info.doi}` : "";
|
|
88
|
+
return `${authorStr}${yearPart}${titlePart}${journalPart}${volPart}${issuePart}${pagesPart}${doiPart}`.trim();
|
|
89
|
+
}
|
|
90
|
+
function formatBibtex(info) {
|
|
91
|
+
const key = info.authors.length > 0
|
|
92
|
+
? info.authors[0].split(" ")[0].toLowerCase() + info.year
|
|
93
|
+
: `pmid${info.pmid}`;
|
|
94
|
+
const authorStr = info.authors.map((a) => {
|
|
95
|
+
const parts = a.split(" ");
|
|
96
|
+
return `${parts[0]}, ${parts.slice(1).join(" ")}`;
|
|
97
|
+
}).join(" and ");
|
|
98
|
+
const lines = [
|
|
99
|
+
`@article{${key},`,
|
|
100
|
+
` author = {${authorStr}},`,
|
|
101
|
+
` title = {${info.title}},`,
|
|
102
|
+
` journal = {${info.journal}},`,
|
|
103
|
+
` year = {${info.year}},`,
|
|
104
|
+
];
|
|
105
|
+
if (info.volume)
|
|
106
|
+
lines.push(` volume = {${info.volume}},`);
|
|
107
|
+
if (info.issue)
|
|
108
|
+
lines.push(` number = {${info.issue}},`);
|
|
109
|
+
if (info.pages)
|
|
110
|
+
lines.push(` pages = {${info.pages}},`);
|
|
111
|
+
if (info.doi)
|
|
112
|
+
lines.push(` doi = {${info.doi}},`);
|
|
113
|
+
lines.push(` pmid = {${info.pmid}},`);
|
|
114
|
+
lines.push(`}`);
|
|
115
|
+
return lines.join("\n");
|
|
116
|
+
}
|
|
117
|
+
export function registerCiteTool(server) {
|
|
118
|
+
server.tool("format_citation", "Format a citation for a PubMed article in APA, Vancouver, Harvard, or BibTeX style.", schema, async (params) => {
|
|
119
|
+
try {
|
|
120
|
+
const xml = await efetch({ id: params.pmid, rettype: "xml" });
|
|
121
|
+
const parsed = parseXml(xml);
|
|
122
|
+
const articles = parsed.PubmedArticleSet?.PubmedArticle;
|
|
123
|
+
if (!articles || (Array.isArray(articles) && articles.length === 0)) {
|
|
124
|
+
return {
|
|
125
|
+
content: [{ type: "text", text: `No article found for PMID ${params.pmid}` }],
|
|
126
|
+
isError: true,
|
|
127
|
+
};
|
|
128
|
+
}
|
|
129
|
+
const article = Array.isArray(articles) ? articles[0] : articles;
|
|
130
|
+
const medlineCitation = article.MedlineCitation;
|
|
131
|
+
const articleData = medlineCitation?.Article;
|
|
132
|
+
if (!articleData) {
|
|
133
|
+
return {
|
|
134
|
+
content: [{ type: "text", text: `No article data for PMID ${params.pmid}` }],
|
|
135
|
+
isError: true,
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
const authors = parseAuthors(articleData.AuthorList);
|
|
139
|
+
const journal = articleData.Journal;
|
|
140
|
+
const journalIssue = journal?.JournalIssue;
|
|
141
|
+
let doi = "";
|
|
142
|
+
const elocationIds = articleData.ELocationID;
|
|
143
|
+
if (elocationIds) {
|
|
144
|
+
const ids = Array.isArray(elocationIds) ? elocationIds : [elocationIds];
|
|
145
|
+
for (const eid of ids) {
|
|
146
|
+
if (typeof eid === "object" && eid["@_EIdType"] === "doi") {
|
|
147
|
+
doi = extractText(eid);
|
|
148
|
+
break;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
const info = {
|
|
153
|
+
authors,
|
|
154
|
+
title: extractText(articleData.ArticleTitle),
|
|
155
|
+
journal: extractText(journal?.Title) || extractText(journal?.ISOAbbreviation),
|
|
156
|
+
year: journalIssue?.PubDate?.Year
|
|
157
|
+
? String(journalIssue.PubDate.Year)
|
|
158
|
+
: extractText(journalIssue?.PubDate?.MedlineDate).match(/\d{4}/)?.[0] ?? "",
|
|
159
|
+
volume: journalIssue?.Volume ? String(journalIssue.Volume) : "",
|
|
160
|
+
issue: journalIssue?.Issue ? String(journalIssue.Issue) : "",
|
|
161
|
+
pages: articleData.Pagination?.MedlinePgn ? String(articleData.Pagination.MedlinePgn) : "",
|
|
162
|
+
doi,
|
|
163
|
+
pmid: params.pmid,
|
|
164
|
+
};
|
|
165
|
+
const formatters = {
|
|
166
|
+
apa: formatApa,
|
|
167
|
+
vancouver: formatVancouver,
|
|
168
|
+
harvard: formatHarvard,
|
|
169
|
+
bibtex: formatBibtex,
|
|
170
|
+
};
|
|
171
|
+
const formatted = formatters[params.style](info);
|
|
172
|
+
return {
|
|
173
|
+
content: [{
|
|
174
|
+
type: "text",
|
|
175
|
+
text: JSON.stringify({ pmid: params.pmid, style: params.style, citation: formatted }, null, 2),
|
|
176
|
+
}],
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
catch (error) {
|
|
180
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
181
|
+
return {
|
|
182
|
+
content: [{ type: "text", text: `Error formatting citation: ${message}` }],
|
|
183
|
+
isError: true,
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
//# sourceMappingURL=cite.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cite.js","sourceRoot":"","sources":["../../src/tools/cite.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AACxC,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAE3E,MAAM,MAAM,GAAG;IACb,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC;IACtC,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,gBAAgB,CAAC;CACnG,CAAC;AAcF,SAAS,SAAS,CAAC,IAAiB;IAClC,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC;QACzC,CAAC,CAAC,EAAE;QACJ,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,IAAI,CAAC;YACxB,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;gBACrB,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;gBAC3B,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;gBACtB,MAAM,QAAQ,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;gBACjE,OAAO,GAAG,IAAI,KAAK,QAAQ,EAAE,CAAC;YAChC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;YACf,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;gBACjC,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;gBAC3B,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;gBACtB,MAAM,QAAQ,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;gBACjE,OAAO,GAAG,IAAI,KAAK,QAAQ,EAAE,CAAC;YAChC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,QAAQ,GAAG,CAAC,GAAG,EAAE;gBAC/B,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;gBACnD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;gBAC9B,MAAM,QAAQ,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;gBAC1B,MAAM,QAAQ,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;gBACjE,OAAO,GAAG,QAAQ,KAAK,QAAQ,EAAE,CAAC;YACpC,CAAC,CAAC,EAAE,CAAC;IAEX,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC;IACtD,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,KAAK,GAAG,CAAC;IAClF,MAAM,WAAW,GAAG,KAAK,IAAI,CAAC,OAAO,GAAG,CAAC;IACzC,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;IACxD,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;IACtD,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IACtD,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,oBAAoB,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAE/D,OAAO,GAAG,SAAS,GAAG,QAAQ,GAAG,SAAS,GAAG,WAAW,GAAG,OAAO,GAAG,SAAS,GAAG,SAAS,IAAI,OAAO,EAAE,CAAC,IAAI,EAAE,CAAC;AACjH,CAAC;AAED,SAAS,eAAe,CAAC,IAAiB;IACxC,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC;QACzC,CAAC,CAAC,EAAE;QACJ,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,IAAI,CAAC;YACxB,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;gBACrB,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;gBAC3B,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;gBACtB,MAAM,QAAQ,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;gBAC1D,OAAO,GAAG,IAAI,IAAI,QAAQ,EAAE,CAAC;YAC/B,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;YACf,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;gBACjC,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;gBAC3B,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;gBACtB,MAAM,QAAQ,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;gBAC1D,OAAO,GAAG,IAAI,IAAI,QAAQ,EAAE,CAAC;YAC/B,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,SAAS,CAAC;IAEhC,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,KAAK,GAAG,CAAC;IAClF,MAAM,WAAW,GAAG,IAAI,IAAI,CAAC,OAAO,GAAG,CAAC;IACxC,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAClD,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IACrD,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;IACtD,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IACrD,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAEnD,OAAO,GAAG,SAAS,IAAI,SAAS,GAAG,WAAW,GAAG,QAAQ,GAAG,OAAO,GAAG,SAAS,GAAG,SAAS,IAAI,OAAO,EAAE,CAAC,IAAI,EAAE,CAAC;AAClH,CAAC;AAED,SAAS,aAAa,CAAC,IAAiB;IACtC,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC;QACzC,CAAC,CAAC,EAAE;QACJ,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,IAAI,CAAC;YACxB,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;gBACrB,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;gBAC3B,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;gBACtB,MAAM,QAAQ,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;gBAChE,OAAO,GAAG,IAAI,KAAK,QAAQ,EAAE,CAAC;YAChC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;YACf,CAAC,CAAC,CAAC,GAAG,EAAE;gBACJ,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;gBAC9B,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;gBAC/B,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;gBACtB,MAAM,QAAQ,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;gBAChE,OAAO,GAAG,IAAI,KAAK,QAAQ,SAAS,CAAC;YACvC,CAAC,CAAC,EAAE,CAAC;IAEX,MAAM,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;IACpD,MAAM,SAAS,GAAG,KAAK,IAAI,CAAC,KAAK,IAAI,CAAC;IACtC,MAAM,WAAW,GAAG,KAAK,IAAI,CAAC,OAAO,GAAG,CAAC;IACzC,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IACtD,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;IACtD,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAC1D,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,SAAS,IAAI,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAEpD,OAAO,GAAG,SAAS,GAAG,QAAQ,GAAG,SAAS,GAAG,WAAW,GAAG,OAAO,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,EAAE,CAAC,IAAI,EAAE,CAAC;AAChH,CAAC;AAED,SAAS,YAAY,CAAC,IAAiB;IACrC,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC;QACjC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,IAAI,CAAC,IAAI;QACzD,CAAC,CAAC,OAAO,IAAI,CAAC,IAAI,EAAE,CAAC;IAEvB,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QACvC,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC3B,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;IACpD,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAEjB,MAAM,KAAK,GAAG;QACZ,YAAY,GAAG,GAAG;QAClB,gBAAgB,SAAS,IAAI;QAC7B,gBAAgB,IAAI,CAAC,KAAK,IAAI;QAC9B,gBAAgB,IAAI,CAAC,OAAO,IAAI;QAChC,gBAAgB,IAAI,CAAC,IAAI,IAAI;KAC9B,CAAC;IAEF,IAAI,IAAI,CAAC,MAAM;QAAE,KAAK,CAAC,IAAI,CAAC,gBAAgB,IAAI,CAAC,MAAM,IAAI,CAAC,CAAC;IAC7D,IAAI,IAAI,CAAC,KAAK;QAAE,KAAK,CAAC,IAAI,CAAC,gBAAgB,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC;IAC3D,IAAI,IAAI,CAAC,KAAK;QAAE,KAAK,CAAC,IAAI,CAAC,gBAAgB,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC;IAC3D,IAAI,IAAI,CAAC,GAAG;QAAE,KAAK,CAAC,IAAI,CAAC,gBAAgB,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC;IACvD,KAAK,CAAC,IAAI,CAAC,gBAAgB,IAAI,CAAC,IAAI,IAAI,CAAC,CAAC;IAC1C,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAEhB,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,MAAiB;IAChD,MAAM,CAAC,IAAI,CACT,iBAAiB,EACjB,qFAAqF,EACrF,MAAM,EACN,KAAK,EAAE,MAAM,EAAE,EAAE;QACf,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,EAAE,EAAE,EAAE,MAAM,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;YAC9D,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC;YAE7B,MAAM,QAAQ,GAAG,MAAM,CAAC,gBAAgB,EAAE,aAAa,CAAC;YACxD,IAAI,CAAC,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,CAAC,EAAE,CAAC;gBACpE,OAAO;oBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,6BAA6B,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC;oBAC7E,OAAO,EAAE,IAAI;iBACd,CAAC;YACJ,CAAC;YAED,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;YACjE,MAAM,eAAe,GAAG,OAAO,CAAC,eAAe,CAAC;YAChD,MAAM,WAAW,GAAG,eAAe,EAAE,OAAO,CAAC;YAE7C,IAAI,CAAC,WAAW,EAAE,CAAC;gBACjB,OAAO;oBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,4BAA4B,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC;oBAC5E,OAAO,EAAE,IAAI;iBACd,CAAC;YACJ,CAAC;YAED,MAAM,OAAO,GAAG,YAAY,CAAC,WAAW,CAAC,UAAU,CAAC,CAAC;YACrD,MAAM,OAAO,GAAG,WAAW,CAAC,OAAO,CAAC;YACpC,MAAM,YAAY,GAAG,OAAO,EAAE,YAAY,CAAC;YAE3C,IAAI,GAAG,GAAG,EAAE,CAAC;YACb,MAAM,YAAY,GAAG,WAAW,CAAC,WAAW,CAAC;YAC7C,IAAI,YAAY,EAAE,CAAC;gBACjB,MAAM,GAAG,GAAG,KAAK,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC;gBACxE,KAAK,MAAM,GAAG,IAAI,GAAG,EAAE,CAAC;oBACtB,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,GAAG,CAAC,WAAW,CAAC,KAAK,KAAK,EAAE,CAAC;wBAC1D,GAAG,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;wBACvB,MAAM;oBACR,CAAC;gBACH,CAAC;YACH,CAAC;YAED,MAAM,IAAI,GAAgB;gBACxB,OAAO;gBACP,KAAK,EAAE,WAAW,CAAC,WAAW,CAAC,YAAY,CAAC;gBAC5C,OAAO,EAAE,WAAW,CAAC,OAAO,EAAE,KAAK,CAAC,IAAI,WAAW,CAAC,OAAO,EAAE,eAAe,CAAC;gBAC7E,IAAI,EAAE,YAAY,EAAE,OAAO,EAAE,IAAI;oBAC/B,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC;oBACnC,CAAC,CAAC,WAAW,CAAC,YAAY,EAAE,OAAO,EAAE,WAAW,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE;gBAC7E,MAAM,EAAE,YAAY,EAAE,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE;gBAC/D,KAAK,EAAE,YAAY,EAAE,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE;gBAC5D,KAAK,EAAE,WAAW,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,WAAW,CAAC,UAAU,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,EAAE;gBAC1F,GAAG;gBACH,IAAI,EAAE,MAAM,CAAC,IAAI;aAClB,CAAC;YAEF,MAAM,UAAU,GAAkD;gBAChE,GAAG,EAAE,SAAS;gBACd,SAAS,EAAE,eAAe;gBAC1B,OAAO,EAAE,aAAa;gBACtB,MAAM,EAAE,YAAY;aACrB,CAAC;YAEF,MAAM,SAAS,GAAG,UAAU,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,CAAC;YAEjD,OAAO;gBACL,OAAO,EAAE,CAAC;wBACR,IAAI,EAAE,MAAM;wBACZ,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;qBAC/F,CAAC;aACH,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACvE,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,8BAA8B,OAAO,EAAE,EAAE,CAAC;gBAC1E,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compare-labels.d.ts","sourceRoot":"","sources":["../../src/tools/compare-labels.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAgFpE,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAwEjE"}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { searchDrugLabels, fetchSplXml } from "../lib/dailymed.js";
|
|
3
|
+
import { searchEmc, fetchSmpcHtml, parseSmpcSections } from "../lib/emc.js";
|
|
4
|
+
import { parseXml, parseSplSections } from "../lib/xml-parser.js";
|
|
5
|
+
import { filterSectionMap } from "../lib/label-mapping.js";
|
|
6
|
+
const schema = {
|
|
7
|
+
drug: z.string().describe("Drug name to compare across US and UK labelling"),
|
|
8
|
+
sections: z
|
|
9
|
+
.array(z.string())
|
|
10
|
+
.optional()
|
|
11
|
+
.describe("Specific topics to compare (e.g., ['indications', 'adverse reactions']). Compares all mapped sections if omitted."),
|
|
12
|
+
};
|
|
13
|
+
async function fetchUsSections(drugName, loincCodes) {
|
|
14
|
+
const searchResults = await searchDrugLabels(drugName);
|
|
15
|
+
if (searchResults.length === 0)
|
|
16
|
+
return { sections: new Map(), source: null };
|
|
17
|
+
const drugLower = drugName.toLowerCase();
|
|
18
|
+
const sorted = [...searchResults].sort((a, b) => {
|
|
19
|
+
const aMatch = a.title.toLowerCase().includes(drugLower) ? 1 : 0;
|
|
20
|
+
const bMatch = b.title.toLowerCase().includes(drugLower) ? 1 : 0;
|
|
21
|
+
if (aMatch !== bMatch)
|
|
22
|
+
return bMatch - aMatch;
|
|
23
|
+
return b.published_date.localeCompare(a.published_date);
|
|
24
|
+
});
|
|
25
|
+
const best = sorted[0];
|
|
26
|
+
const xml = await fetchSplXml(best.setid);
|
|
27
|
+
const parsed = parseXml(xml);
|
|
28
|
+
const docComponent = parsed?.document?.component;
|
|
29
|
+
const firstComponent = Array.isArray(docComponent) ? docComponent[0] : docComponent;
|
|
30
|
+
const structuredBody = firstComponent?.structuredBody;
|
|
31
|
+
const rawSections = parseSplSections(structuredBody, loincCodes);
|
|
32
|
+
const sectionMap = new Map();
|
|
33
|
+
for (const s of rawSections) {
|
|
34
|
+
sectionMap.set(s.code, { code: s.code, title: s.title, content: s.content });
|
|
35
|
+
}
|
|
36
|
+
return {
|
|
37
|
+
sections: sectionMap,
|
|
38
|
+
source: `https://dailymed.nlm.nih.gov/dailymed/drugInfo.cfm?setid=${best.setid}`,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
async function fetchUkSections(drugName, ukCodes) {
|
|
42
|
+
const searchResults = await searchEmc(drugName);
|
|
43
|
+
if (searchResults.length === 0)
|
|
44
|
+
return { sections: new Map(), source: null };
|
|
45
|
+
const drugLower = drugName.toLowerCase();
|
|
46
|
+
const sorted = [...searchResults].sort((a, b) => {
|
|
47
|
+
const aMatch = a.name.toLowerCase().includes(drugLower) ? 1 : 0;
|
|
48
|
+
const bMatch = b.name.toLowerCase().includes(drugLower) ? 1 : 0;
|
|
49
|
+
return bMatch - aMatch;
|
|
50
|
+
});
|
|
51
|
+
const best = sorted[0];
|
|
52
|
+
const html = await fetchSmpcHtml(best.product_id);
|
|
53
|
+
const rawSections = parseSmpcSections(html, ukCodes);
|
|
54
|
+
const sectionMap = new Map();
|
|
55
|
+
for (const s of rawSections) {
|
|
56
|
+
sectionMap.set(s.code, { code: s.code, title: s.title, content: s.content });
|
|
57
|
+
}
|
|
58
|
+
return {
|
|
59
|
+
sections: sectionMap,
|
|
60
|
+
source: `https://www.medicines.org.uk/emc/product/${best.product_id}/smpc`,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
export function registerCompareLabelsTool(server) {
|
|
64
|
+
server.tool("compare_labels", "Compare US FDA Prescribing Information vs UK/EU SmPC for a drug side-by-side. Maps equivalent sections (e.g., US Indications ↔ UK 4.1) and returns paired content.", schema, async (params) => {
|
|
65
|
+
try {
|
|
66
|
+
const mappings = filterSectionMap(params.sections);
|
|
67
|
+
if (mappings.length === 0) {
|
|
68
|
+
return {
|
|
69
|
+
content: [{
|
|
70
|
+
type: "text",
|
|
71
|
+
text: JSON.stringify({ error: "No matching section mappings found for the requested topics" }, null, 2),
|
|
72
|
+
}],
|
|
73
|
+
isError: true,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
const loincCodes = mappings.map((m) => m.us_loinc);
|
|
77
|
+
const ukCodes = mappings.map((m) => m.uk_code);
|
|
78
|
+
// Fetch both in parallel — allow partial results
|
|
79
|
+
const [usResult, ukResult] = await Promise.allSettled([
|
|
80
|
+
fetchUsSections(params.drug, loincCodes),
|
|
81
|
+
fetchUkSections(params.drug, ukCodes),
|
|
82
|
+
]);
|
|
83
|
+
const us = usResult.status === "fulfilled" ? usResult.value : { sections: new Map(), source: null };
|
|
84
|
+
const uk = ukResult.status === "fulfilled" ? ukResult.value : { sections: new Map(), source: null };
|
|
85
|
+
if (us.sections.size === 0 && uk.sections.size === 0) {
|
|
86
|
+
const errors = [];
|
|
87
|
+
if (usResult.status === "rejected")
|
|
88
|
+
errors.push(`US: ${usResult.reason}`);
|
|
89
|
+
if (ukResult.status === "rejected")
|
|
90
|
+
errors.push(`UK: ${ukResult.reason}`);
|
|
91
|
+
return {
|
|
92
|
+
content: [{
|
|
93
|
+
type: "text",
|
|
94
|
+
text: JSON.stringify({
|
|
95
|
+
error: `No labelling found for "${params.drug}" in either US or UK databases`,
|
|
96
|
+
details: errors.length > 0 ? errors : undefined,
|
|
97
|
+
}, null, 2),
|
|
98
|
+
}],
|
|
99
|
+
isError: true,
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
const comparisons = mappings.map((mapping) => ({
|
|
103
|
+
topic: mapping.topic,
|
|
104
|
+
us_section: us.sections.get(mapping.us_loinc) ?? null,
|
|
105
|
+
uk_section: uk.sections.get(mapping.uk_code) ?? null,
|
|
106
|
+
}));
|
|
107
|
+
const result = {
|
|
108
|
+
drug: params.drug,
|
|
109
|
+
comparisons,
|
|
110
|
+
us_source: us.source,
|
|
111
|
+
uk_source: uk.source,
|
|
112
|
+
};
|
|
113
|
+
return {
|
|
114
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
catch (error) {
|
|
118
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
119
|
+
return {
|
|
120
|
+
content: [{ type: "text", text: `Error comparing labels: ${message}` }],
|
|
121
|
+
isError: true,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
//# sourceMappingURL=compare-labels.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compare-labels.js","sourceRoot":"","sources":["../../src/tools/compare-labels.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fulltext.d.ts","sourceRoot":"","sources":["../../src/tools/fulltext.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAkBpE,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAiG5D"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { efetch, pmidToPmcid } from "../lib/ncbi.js";
|
|
3
|
+
import { parseXml, parseJatsSections, parseFigureCaptions, parseTableCaptions, countReferences, extractText, } from "../lib/xml-parser.js";
|
|
4
|
+
const schema = {
|
|
5
|
+
pmid: z.string().optional().describe("PubMed ID"),
|
|
6
|
+
pmcid: z.string().optional().describe("PubMed Central ID (e.g., PMC1234567)"),
|
|
7
|
+
sections: z.array(z.string()).optional().describe("Filter to specific section titles"),
|
|
8
|
+
};
|
|
9
|
+
export function registerFullTextTool(server) {
|
|
10
|
+
server.tool("get_full_text", "Get the full text of an open-access article from PubMed Central. Returns article sections, figure/table captions, and reference count. Only works for articles available in PMC.", schema, async (params) => {
|
|
11
|
+
try {
|
|
12
|
+
if (!params.pmid && !params.pmcid) {
|
|
13
|
+
return {
|
|
14
|
+
content: [{ type: "text", text: "Either pmid or pmcid is required" }],
|
|
15
|
+
isError: true,
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
let pmcid = params.pmcid ?? null;
|
|
19
|
+
const pmid = params.pmid ?? "";
|
|
20
|
+
// Convert PMID to PMCID if needed
|
|
21
|
+
if (!pmcid && pmid) {
|
|
22
|
+
pmcid = await pmidToPmcid(pmid);
|
|
23
|
+
if (!pmcid) {
|
|
24
|
+
return {
|
|
25
|
+
content: [{
|
|
26
|
+
type: "text",
|
|
27
|
+
text: `No PMC full text available for PMID ${pmid}. The article may not be open access.`,
|
|
28
|
+
}],
|
|
29
|
+
isError: true,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
// Strip PMC prefix for the API call
|
|
34
|
+
const pmcIdNum = pmcid.replace(/^PMC/i, "");
|
|
35
|
+
const xml = await efetch({
|
|
36
|
+
db: "pmc",
|
|
37
|
+
id: pmcIdNum,
|
|
38
|
+
rettype: "xml",
|
|
39
|
+
});
|
|
40
|
+
const parsed = parseXml(xml);
|
|
41
|
+
const pmcArticle = parsed["pmc-articleset"]?.article ?? parsed.article;
|
|
42
|
+
if (!pmcArticle) {
|
|
43
|
+
return {
|
|
44
|
+
content: [{ type: "text", text: `Could not parse full text for ${pmcid}` }],
|
|
45
|
+
isError: true,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
const front = pmcArticle.front;
|
|
49
|
+
const body = pmcArticle.body;
|
|
50
|
+
const back = pmcArticle.back;
|
|
51
|
+
// Extract title
|
|
52
|
+
const articleMeta = front?.["article-meta"];
|
|
53
|
+
const title = articleMeta?.["title-group"]?.["article-title"]
|
|
54
|
+
? extractText(articleMeta["title-group"]["article-title"])
|
|
55
|
+
: "";
|
|
56
|
+
// Parse sections
|
|
57
|
+
let sections = parseJatsSections(body);
|
|
58
|
+
// Filter to requested sections
|
|
59
|
+
if (params.sections && params.sections.length > 0) {
|
|
60
|
+
const requested = params.sections.map((s) => s.toLowerCase());
|
|
61
|
+
sections = sections.filter((s) => requested.some((r) => s.title.toLowerCase().includes(r)));
|
|
62
|
+
}
|
|
63
|
+
const figureCaptions = parseFigureCaptions(body);
|
|
64
|
+
const tableCaptions = parseTableCaptions(body);
|
|
65
|
+
const referenceCount = countReferences(back);
|
|
66
|
+
const result = {
|
|
67
|
+
pmid: pmid,
|
|
68
|
+
pmcid: pmcid,
|
|
69
|
+
title,
|
|
70
|
+
sections,
|
|
71
|
+
figure_captions: figureCaptions,
|
|
72
|
+
table_captions: tableCaptions,
|
|
73
|
+
reference_count: referenceCount,
|
|
74
|
+
};
|
|
75
|
+
return {
|
|
76
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
catch (error) {
|
|
80
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
81
|
+
return {
|
|
82
|
+
content: [{ type: "text", text: `Error fetching full text: ${message}` }],
|
|
83
|
+
isError: true,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
//# sourceMappingURL=fulltext.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fulltext.js","sourceRoot":"","sources":["../../src/tools/fulltext.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"related.d.ts","sourceRoot":"","sources":["../../src/tools/related.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAUpE,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAgE3D"}
|