@a9i5k4/dsh-literature 0.2.8 → 0.2.11

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.
Files changed (3) hide show
  1. package/lib/client.js +69 -13
  2. package/lib/index.js +108 -30
  3. package/package.json +1 -1
package/lib/index.js CHANGED
@@ -1768,15 +1768,52 @@ var cite_exports = {};
1768
1768
  __export(cite_exports, {
1769
1769
  bibtex: () => bibtex,
1770
1770
  cite: () => cite,
1771
- listStyles: () => listStyles
1771
+ citeDetailed: () => citeDetailed,
1772
+ listStyles: () => listStyles,
1773
+ segmentsToHtml: () => segmentsToHtml,
1774
+ stripItalic: () => stripItalic,
1775
+ toSegments: () => toSegments
1772
1776
  });
1773
- function authorsList(record, { max = 99, ellipsis = ", et al." } = {}) {
1777
+ function apaInitials(firstName) {
1778
+ const s = String(firstName ?? "").trim();
1779
+ if (!s) return "";
1780
+ return s.charAt(0).toUpperCase() + ".";
1781
+ }
1782
+ function apaAuthors(record) {
1774
1783
  const list = record.authors ?? [];
1775
1784
  if (!list.length) return "";
1776
- const names = list.map((a) => [a.lastName, a.firstName].filter(Boolean).join(", "));
1777
- if (names.length === 1) return names[0];
1778
- if (names.length <= max) return names.slice(0, -1).join(", ") + ", & " + names[names.length - 1];
1779
- return names.slice(0, max).join(", ") + ellipsis;
1785
+ const name2 = (a) => {
1786
+ if (CJK.test(a.lastName ?? "") || CJK.test(a.firstName ?? "")) return `${a.lastName ?? ""}${a.firstName ?? ""}`;
1787
+ return [a.lastName, apaInitials(a.firstName)].filter(Boolean).join(", ");
1788
+ };
1789
+ if (list.length === 1) return name2(list[0]);
1790
+ if (list.length <= 20) {
1791
+ const names = list.map(name2);
1792
+ return names.slice(0, -1).join(", ") + ", & " + names[names.length - 1];
1793
+ }
1794
+ return list.slice(0, 19).map(name2).join(", ") + ", \u2026 " + name2(list[list.length - 1]);
1795
+ }
1796
+ function mlaAuthors(record) {
1797
+ const list = record.authors ?? [];
1798
+ if (!list.length) return "";
1799
+ const inverted = (a) => [a.lastName, a.firstName].filter(Boolean).join(", ");
1800
+ const upright = (a) => [a.firstName, a.lastName].filter(Boolean).join(" ");
1801
+ if (list.length === 1) return inverted(list[0]);
1802
+ if (list.length === 2) return inverted(list[0]) + ", and " + upright(list[1]);
1803
+ return inverted(list[0]) + ", et al";
1804
+ }
1805
+ function chicagoAuthors(record) {
1806
+ const list = record.authors ?? [];
1807
+ if (!list.length) return "";
1808
+ const inverted = (a) => [a.lastName, a.firstName].filter(Boolean).join(", ");
1809
+ const upright = (a) => [a.firstName, a.lastName].filter(Boolean).join(" ");
1810
+ if (list.length === 1) return inverted(list[0]);
1811
+ if (list.length === 2) return inverted(list[0]) + ", and " + upright(list[1]);
1812
+ if (list.length <= 10) {
1813
+ const parts = [inverted(list[0]), ...list.slice(1, -1).map(upright)];
1814
+ return parts.join(", ") + ", and " + upright(list[list.length - 1]);
1815
+ }
1816
+ return list.slice(0, 7).map(inverted).join(", ") + ", et al";
1780
1817
  }
1781
1818
  function authorsShort(record) {
1782
1819
  const list = record.authors ?? [];
@@ -1796,13 +1833,13 @@ function doiUrl(record) {
1796
1833
  return record.doi ? `https://doi.org/${record.doi}` : record.url ?? "";
1797
1834
  }
1798
1835
  function apa(record) {
1799
- const authors2 = authorsList(record, { max: 20 });
1800
- const who = authors2 ? `${authors2}. ` : "";
1836
+ const authors2 = apaAuthors(record);
1837
+ const who = authors2 ? `${authors2} ` : "";
1801
1838
  const year = `(${yearStr(record)}). `;
1802
1839
  const title = (record.title ?? "Untitled").trim();
1803
1840
  if (record.itemType === "journalArticle" || record.itemType === "preprint") {
1804
1841
  const journal = record.container ? `*${record.container}*, ` : "";
1805
- const vol = record.volume ? `${record.volume}` : "";
1842
+ const vol = record.volume ? `*${record.volume}*` : "";
1806
1843
  const issue = record.issue ? `(${record.issue})` : "";
1807
1844
  const pages = pagesStr(record) ? `, ${pagesStr(record)}` : "";
1808
1845
  const volPart = vol || issue || pages ? `${vol}${issue}${pages}. ` : "";
@@ -1829,10 +1866,16 @@ function apa(record) {
1829
1866
  }
1830
1867
  function gb(record) {
1831
1868
  const list = record.authors ?? [];
1869
+ const cjk = (s) => /[\u4e00-\u9fff]/.test(s ?? "");
1870
+ const gbName = (a) => {
1871
+ if (cjk(a.lastName) || cjk(a.firstName)) return `${a.lastName ?? ""}${a.firstName ?? ""}`;
1872
+ const ini = String(a.firstName ?? "").trim();
1873
+ return [a.lastName, ini ? ini.charAt(0).toUpperCase() : ""].filter(Boolean).join(" ");
1874
+ };
1832
1875
  let who;
1833
1876
  if (!list.length) who = "";
1834
- else if (list.length <= 3) who = list.map((a) => `${a.lastName}${a.firstName ? " " + a.firstName : ""}`).join(", ");
1835
- else who = `${list.slice(0, 3).map((a) => `${a.lastName}${a.firstName ? " " + a.firstName : ""}`).join(", ")}, \u7B49`;
1877
+ else if (list.length <= 3) who = list.map(gbName).join(", ");
1878
+ else who = `${list.slice(0, 3).map(gbName).join(", ")}, \u7B49`;
1836
1879
  const whoPart = who ? `${who}. ` : "";
1837
1880
  const title = (record.title ?? "").trim();
1838
1881
  const year = yearStr(record);
@@ -1861,8 +1904,8 @@ function gb(record) {
1861
1904
  return `${whoPart}${title}[Z]. ${year}.`.trim();
1862
1905
  }
1863
1906
  function mla(record) {
1864
- const list = record.authors ?? [];
1865
- const who = list.length ? list.map((a) => `${a.lastName}, ${a.firstName ?? ""}`.trim()).join(", ") + ". " : "";
1907
+ const who0 = mlaAuthors(record);
1908
+ const who = who0 ? who0 + ". " : "";
1866
1909
  const title = (record.title ?? "Untitled").trim();
1867
1910
  if (record.itemType === "journalArticle" || record.itemType === "preprint") {
1868
1911
  const journal = record.container ? ` *${record.container}*, ` : "";
@@ -1880,15 +1923,15 @@ function mla(record) {
1880
1923
  return `${who}"${title}." ${record.publisher ?? ""} ${yearStr(record)}.`.trim();
1881
1924
  }
1882
1925
  function chicago(record) {
1883
- const list = record.authors ?? [];
1884
- const who = list.length ? list.map((a) => `${a.firstName ?? ""} ${a.lastName ?? ""}`.trim()).join(", ") + ". " : "";
1926
+ const who0 = chicagoAuthors(record);
1927
+ const who = who0 ? who0 + ". " : "";
1885
1928
  const title = (record.title ?? "Untitled").trim();
1886
1929
  if (record.itemType === "journalArticle" || record.itemType === "preprint") {
1887
- const journal = record.container ? ` "${record.container}"` : "";
1930
+ const journal = record.container ? ` *${record.container}*` : "";
1888
1931
  const vol = record.volume ? ` ${record.volume}` : "";
1889
1932
  const issue = record.issue ? `, no. ${record.issue}` : "";
1890
1933
  const pages = pagesStr(record) ? `: ${pagesStr(record)}` : "";
1891
- return `${who}"${title}.${journal}" ${vol}${issue} (${yearStr(record)})${pages}.`.trim();
1934
+ return `${who}"${title}."${journal}${vol}${issue} (${yearStr(record)})${pages}.`.replace(/\s+/g, " ").replace(/ ,/g, ",").trim();
1892
1935
  }
1893
1936
  const pub = record.publisher ? ` ${record.publisher},` : "";
1894
1937
  return `${who}*${title}.*${pub} ${yearStr(record)}.`.trim();
@@ -1930,36 +1973,71 @@ function bibtex(record) {
1930
1973
  const body = fields.map(([k, v]) => ` ${k} = {${bibtexEscape(v)}}`).join(",\n");
1931
1974
  return "@" + type + "{" + key + ",\n" + body + "\n}\n";
1932
1975
  }
1976
+ function stripItalic(text) {
1977
+ return String(text ?? "").replace(/\*([^*]+)\*/g, "$1");
1978
+ }
1979
+ function toSegments(text) {
1980
+ const s = String(text ?? "");
1981
+ const out = [];
1982
+ const re = /\*([^*]+)\*/g;
1983
+ let last = 0;
1984
+ let m;
1985
+ while (m = re.exec(s)) {
1986
+ if (m.index > last) out.push({ text: s.slice(last, m.index) });
1987
+ out.push({ text: m[1], italic: true });
1988
+ last = m.index + m[0].length;
1989
+ }
1990
+ if (last < s.length) out.push({ text: s.slice(last) });
1991
+ return out.length ? out : [{ text: s }];
1992
+ }
1993
+ function escapeHtml(text) {
1994
+ return String(text ?? "").replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
1995
+ }
1996
+ function segmentsToHtml(segments) {
1997
+ return segments.map((seg) => seg.italic ? `<i>${escapeHtml(seg.text)}</i>` : escapeHtml(seg.text)).join("");
1998
+ }
1933
1999
  function cite(record, opts = {}) {
2000
+ return citeDetailed(record, opts).text;
2001
+ }
2002
+ function citeDetailed(record, opts = {}) {
1934
2003
  const style = STYLES[opts.style] ?? STYLES.apa;
1935
2004
  const mode = opts.mode ?? "reference";
1936
- if (opts.style === "bibtex") return style.format(record);
2005
+ if (opts.style === "bibtex") {
2006
+ const text2 = style.format(record);
2007
+ return { text: text2, segments: [{ text: text2 }], html: escapeHtml(text2), style: opts.style, mode: "reference" };
2008
+ }
2009
+ let raw;
1937
2010
  if (mode === "intext") {
1938
2011
  if (opts.style === "gb") {
1939
- return `\uFF08${authorsShortGb(record)}\uFF0C${yearStr(record)}\uFF09`;
2012
+ raw = `\uFF08${authorsShortGb(record)}\uFF0C${yearStr(record)}\uFF09`;
2013
+ } else {
2014
+ raw = `(${authorsShort(record)}, ${yearStr(record)})`;
1940
2015
  }
1941
- return `(${authorsShort(record)}, ${yearStr(record)})`;
1942
- }
1943
- if (mode === "direct") {
2016
+ } else if (mode === "direct") {
1944
2017
  const pages = opts.pages ? opts.style === "gb" ? `\uFF0C\u7B2C ${opts.pages} \u9875` : `, p. ${opts.pages}` : "";
1945
- if (opts.style === "gb") return `\u201C${(record.title ?? "").trim()}\u201D\uFF08${authorsShortGb(record)}\uFF0C${yearStr(record)}${pages}\uFF09`;
1946
- return `"${(record.title ?? "").trim()}" (${authorsShort(record)}, ${yearStr(record)}${pages})`;
2018
+ if (opts.style === "gb") raw = `\u201C${(record.title ?? "").trim()}\u201D\uFF08${authorsShortGb(record)}\uFF0C${yearStr(record)}${pages}\uFF09`;
2019
+ else raw = `"${(record.title ?? "").trim()}" (${authorsShort(record)}, ${yearStr(record)}${pages})`;
2020
+ } else {
2021
+ raw = style.format(record);
1947
2022
  }
1948
- return style.format(record);
2023
+ const text = stripItalic(raw);
2024
+ const segments = toSegments(raw);
2025
+ return { text, segments, html: segmentsToHtml(segments), style: opts.style ?? "apa", mode };
1949
2026
  }
1950
2027
  function authorsShortGb(record) {
1951
2028
  const list = record.authors ?? [];
1952
2029
  if (!list.length) return "\u4F5A\u540D";
1953
2030
  if (list.length === 1) return list[0].lastName;
1954
2031
  if (list.length === 2) return `${list[0].lastName}\u3001${list[1].lastName}`;
1955
- return `${list[0].lastName}\u7B49`;
2032
+ return `${list[0].lastName} \u7B49`;
1956
2033
  }
1957
2034
  function listStyles() {
1958
2035
  return Object.entries(STYLES).map(([id, s]) => ({ id, label: s.label }));
1959
2036
  }
1960
- var STYLES;
2037
+ var CJK, STYLES;
1961
2038
  var init_cite = __esm({
1962
2039
  "src/node/cite.js"() {
2040
+ CJK = /[\u4e00-\u9fff]/;
1963
2041
  STYLES = {
1964
2042
  apa: { label: "APA 7th", format: apa },
1965
2043
  gb: { label: "GB/T 7714-2015", format: gb },
@@ -35823,13 +35901,13 @@ async function handler(req, res, ctx) {
35823
35901
  writeJson(res, 404, { error: "\u6761\u76EE\u7F3A\u5C11\u5143\u6570\u636E\uFF0C\u65E0\u6CD5\u751F\u6210\u5F15\u7528", code: "noMetadataCite" });
35824
35902
  return;
35825
35903
  }
35826
- const { cite: cite2 } = await Promise.resolve().then(() => (init_cite(), cite_exports));
35827
- const text = cite2(item.record, {
35904
+ const { citeDetailed: citeDetailed2 } = await Promise.resolve().then(() => (init_cite(), cite_exports));
35905
+ const detail = citeDetailed2(item.record, {
35828
35906
  style: body?.style ?? "apa",
35829
35907
  mode: body?.mode ?? "reference",
35830
35908
  pages: body?.pages
35831
35909
  });
35832
- writeJson(res, 200, { text, style: body?.style ?? "apa", mode: body?.mode ?? "reference" });
35910
+ writeJson(res, 200, { ...detail, style: body?.style ?? "apa", mode: body?.mode ?? "reference" });
35833
35911
  return;
35834
35912
  }
35835
35913
  if (head === "scan-dir" && methodOk(req, "POST")) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@a9i5k4/dsh-literature",
3
- "version": "0.2.8",
3
+ "version": "0.2.11",
4
4
  "description": "DSH Literature 文献侧窗:在 DeepSeek Harness 侧边栏识别 DOI/arXiv/标题、抓取元数据与全文、写入本地文献库或导出目录,并提供内置 PDF 阅读器(缩放/翻页/目录/搜索/高亮/笔记)。",
5
5
  "type": "module",
6
6
  "main": "lib/index.js",