From 48450d4631604d0e9d5b8993cb7db1568f0be340 Mon Sep 17 00:00:00 2001 From: sadok Date: Wed, 5 Nov 2025 15:51:55 +0100 Subject: [PATCH 01/36] modification des fichiers qui font la configuration des exporters --- .../src/main/java/org/jabref/logic/exporter/ExporterFactory.java | 1 + jablib/src/main/resources/l10n/JabRef_en.properties | 1 + 2 files changed, 2 insertions(+) diff --git a/jablib/src/main/java/org/jabref/logic/exporter/ExporterFactory.java b/jablib/src/main/java/org/jabref/logic/exporter/ExporterFactory.java index b9125600c9e..3da162b34e3 100644 --- a/jablib/src/main/java/org/jabref/logic/exporter/ExporterFactory.java +++ b/jablib/src/main/java/org/jabref/logic/exporter/ExporterFactory.java @@ -54,6 +54,7 @@ public static ExporterFactory create(CliPreferences preferences) { exporters.add(new TemplateExporter("MIS Quarterly", "misq", "misq", "misq", StandardFileType.RTF, layoutPreferences, saveOrder)); exporters.add(new TemplateExporter("CSL YAML", "yaml", "yaml", null, StandardFileType.YAML, layoutPreferences, saveOrder, BlankLineBehaviour.DELETE_BLANKS)); exporters.add(new TemplateExporter("Hayagriva YAML", "hayagrivayaml", "hayagrivayaml", null, StandardFileType.YAML, layoutPreferences, saveOrder, BlankLineBehaviour.DELETE_BLANKS)); + exporters.add(new TemplateExporter(Localization.lang("Markdown academicpages"), "academicpages", "academicpages", "academicpages", StandardFileType.MARKDOWN, layoutPreferences, saveOrder)); exporters.add(new OpenOfficeDocumentCreator()); exporters.add(new OpenDocumentSpreadsheetCreator()); exporters.add(new MSBibExporter()); diff --git a/jablib/src/main/resources/l10n/JabRef_en.properties b/jablib/src/main/resources/l10n/JabRef_en.properties index 9b1b266fd5d..9fb9a7274ba 100644 --- a/jablib/src/main/resources/l10n/JabRef_en.properties +++ b/jablib/src/main/resources/l10n/JabRef_en.properties @@ -472,6 +472,7 @@ The\ marked\ area\ does\ not\ contain\ any\ legible\ text!=The marked area does HTML\ table=HTML table HTML\ table\ (with\ Abstract\ &\ BibTeX)=HTML table (with Abstract & BibTeX) Markdown\ titles=Markdown titles +Markdown\ academicpages=Academic Pages Markdowns Icon=Icon From 65bbc4454cb7e96252240d565983805546df8bf7 Mon Sep 17 00:00:00 2001 From: Lucie Desnoyers Date: Wed, 5 Nov 2025 16:05:08 +0100 Subject: [PATCH 02/36] Adding the empty layouts in resources/resource/layout/academicpages --- .../academicpages/academicpages.page.layout | 0 .../academicpages/academicpages.portfolio.layout | 0 .../academicpages/academicpages.post.layout | 0 .../academicpages.publication.layout | 0 .../academicpages/academicpages.talk.layout | 15 +++++++++++++++ .../academicpages/academicpages.teaching.layout | 0 6 files changed, 15 insertions(+) create mode 100644 jablib/src/main/resources/resource/layout/academicpages/academicpages.page.layout create mode 100644 jablib/src/main/resources/resource/layout/academicpages/academicpages.portfolio.layout create mode 100644 jablib/src/main/resources/resource/layout/academicpages/academicpages.post.layout create mode 100644 jablib/src/main/resources/resource/layout/academicpages/academicpages.publication.layout create mode 100644 jablib/src/main/resources/resource/layout/academicpages/academicpages.talk.layout create mode 100644 jablib/src/main/resources/resource/layout/academicpages/academicpages.teaching.layout diff --git a/jablib/src/main/resources/resource/layout/academicpages/academicpages.page.layout b/jablib/src/main/resources/resource/layout/academicpages/academicpages.page.layout new file mode 100644 index 00000000000..e69de29bb2d diff --git a/jablib/src/main/resources/resource/layout/academicpages/academicpages.portfolio.layout b/jablib/src/main/resources/resource/layout/academicpages/academicpages.portfolio.layout new file mode 100644 index 00000000000..e69de29bb2d diff --git a/jablib/src/main/resources/resource/layout/academicpages/academicpages.post.layout b/jablib/src/main/resources/resource/layout/academicpages/academicpages.post.layout new file mode 100644 index 00000000000..e69de29bb2d diff --git a/jablib/src/main/resources/resource/layout/academicpages/academicpages.publication.layout b/jablib/src/main/resources/resource/layout/academicpages/academicpages.publication.layout new file mode 100644 index 00000000000..e69de29bb2d diff --git a/jablib/src/main/resources/resource/layout/academicpages/academicpages.talk.layout b/jablib/src/main/resources/resource/layout/academicpages/academicpages.talk.layout new file mode 100644 index 00000000000..334957eb5ce --- /dev/null +++ b/jablib/src/main/resources/resource/layout/academicpages/academicpages.talk.layout @@ -0,0 +1,15 @@ +--- +title: "Paper Title Number 1" +collection: publications +category: manuscripts +permalink: /publication/2009-10-01-paper-title-number-1 +excerpt: 'This paper is about the number 1. The number 2 is left for future work.' +date: 2009-10-01 +venue: 'Journal 1' +slidesurl: 'https://academicpages.github.io/files/slides1.pdf' +paperurl: 'https://academicpages.github.io/files/paper1.pdf' +bibtexurl: 'https://academicpages.github.io/files/bibtex1.bib' +citation: 'Your Name, You. (2009). "Paper Title Number 1." Journal 1. 1(1).' +--- + +* \format[RemoveLatexCommands,HTMLChars]{\title}. \begin{journal}\format[RemoveLatexCommands,HTMLChars]{\journal}\end{journal}\begin{year} \format{\year}\end{year} diff --git a/jablib/src/main/resources/resource/layout/academicpages/academicpages.teaching.layout b/jablib/src/main/resources/resource/layout/academicpages/academicpages.teaching.layout new file mode 100644 index 00000000000..e69de29bb2d From a4e2fea4861044bf6ec5d3c9cf89add4f8e2da2c Mon Sep 17 00:00:00 2001 From: sadok Date: Wed, 5 Nov 2025 17:27:01 +0100 Subject: [PATCH 03/36] =?UTF-8?q?cr=C3=A9ation=20du=20fichier=20academicpa?= =?UTF-8?q?ges.article.layout?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../academicpages/academicpages.article.layout | 13 +++++++++++++ .../academicpages/academicpages.publication.layout | 1 + 2 files changed, 14 insertions(+) create mode 100644 jablib/src/main/resources/resource/layout/academicpages/academicpages.article.layout diff --git a/jablib/src/main/resources/resource/layout/academicpages/academicpages.article.layout b/jablib/src/main/resources/resource/layout/academicpages/academicpages.article.layout new file mode 100644 index 00000000000..e2a6b484a1f --- /dev/null +++ b/jablib/src/main/resources/resource/layout/academicpages/academicpages.article.layout @@ -0,0 +1,13 @@ +--- +title: "\format[RemoveLatexCommands,HTMLChars]{\title}" +collection: publications +category: article +permalink: /publication/\format{\year}-\begin{\month}\format{\month}\end{\month}\begin{!month}\format{(01)}\end{!month}-\begin{\day}\format{\day}\end{\day}\begin{!day}\format{(01)}\end{!day}-\format[RemoveLatexCommands,HTMLChars]{\title} +excerpt: '\begin{\note}\format[RemoveLatexCommands,HTMLChars]{\note}\end{\note}' +date: \format{\year}-\begin{\month}\format{\month}\end{\month}\begin{!month}\format{(01)}\end{!month}-\begin{\day}\format{\day}\end{\day}\begin{!day}\format{(01)}\end{!day} +venue: '\format[RemoveLatexCommands,HTMLChars]{\journal}' +slidesurl: '' +paperurl: '\begin{\url}\format[RemoveLatexCommands,HTMLChars]{\url}\end{\url} \begin{!url}\format{\doi}\end{!url}' +bibtexurl: '' +citation: '\format[HTMLChars]{\author}. (\format{\year}). ""\format[RemoveLatexCommands,HTMLChars]{\title}." \format[RemoveLatexCommands,HTMLChars]{\journal}.' +--- diff --git a/jablib/src/main/resources/resource/layout/academicpages/academicpages.publication.layout b/jablib/src/main/resources/resource/layout/academicpages/academicpages.publication.layout index e69de29bb2d..8b137891791 100644 --- a/jablib/src/main/resources/resource/layout/academicpages/academicpages.publication.layout +++ b/jablib/src/main/resources/resource/layout/academicpages/academicpages.publication.layout @@ -0,0 +1 @@ + From 3e34b92603ba70df612628d7dacc92456c0d7d4e Mon Sep 17 00:00:00 2001 From: sadok Date: Wed, 5 Nov 2025 18:26:12 +0100 Subject: [PATCH 04/36] utilisation du fichier article.layout pour le new TemplateExporter --- .../java/org/jabref/logic/exporter/ExporterFactory.java | 2 +- .../layout/academicpages/academicpages.article.layout | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/jablib/src/main/java/org/jabref/logic/exporter/ExporterFactory.java b/jablib/src/main/java/org/jabref/logic/exporter/ExporterFactory.java index 3da162b34e3..9e2454ecab2 100644 --- a/jablib/src/main/java/org/jabref/logic/exporter/ExporterFactory.java +++ b/jablib/src/main/java/org/jabref/logic/exporter/ExporterFactory.java @@ -54,7 +54,7 @@ public static ExporterFactory create(CliPreferences preferences) { exporters.add(new TemplateExporter("MIS Quarterly", "misq", "misq", "misq", StandardFileType.RTF, layoutPreferences, saveOrder)); exporters.add(new TemplateExporter("CSL YAML", "yaml", "yaml", null, StandardFileType.YAML, layoutPreferences, saveOrder, BlankLineBehaviour.DELETE_BLANKS)); exporters.add(new TemplateExporter("Hayagriva YAML", "hayagrivayaml", "hayagrivayaml", null, StandardFileType.YAML, layoutPreferences, saveOrder, BlankLineBehaviour.DELETE_BLANKS)); - exporters.add(new TemplateExporter(Localization.lang("Markdown academicpages"), "academicpages", "academicpages", "academicpages", StandardFileType.MARKDOWN, layoutPreferences, saveOrder)); + exporters.add(new TemplateExporter(Localization.lang("Markdown academicpages"), "academicpages", "academicpages.article", "academicpages", StandardFileType.MARKDOWN, layoutPreferences, saveOrder)); exporters.add(new OpenOfficeDocumentCreator()); exporters.add(new OpenDocumentSpreadsheetCreator()); exporters.add(new MSBibExporter()); diff --git a/jablib/src/main/resources/resource/layout/academicpages/academicpages.article.layout b/jablib/src/main/resources/resource/layout/academicpages/academicpages.article.layout index e2a6b484a1f..ccde8a2d241 100644 --- a/jablib/src/main/resources/resource/layout/academicpages/academicpages.article.layout +++ b/jablib/src/main/resources/resource/layout/academicpages/academicpages.article.layout @@ -2,12 +2,12 @@ title: "\format[RemoveLatexCommands,HTMLChars]{\title}" collection: publications category: article -permalink: /publication/\format{\year}-\begin{\month}\format{\month}\end{\month}\begin{!month}\format{(01)}\end{!month}-\begin{\day}\format{\day}\end{\day}\begin{!day}\format{(01)}\end{!day}-\format[RemoveLatexCommands,HTMLChars]{\title} +permalink: /publication/\format{\year}-\begin{\month}\format{\month}\end{\month}\begin{!month}01\end{!month}-\begin{\day}\format{\day}\end{\day}\begin{!day}01\end{!day}-\format[RemoveLatexCommands,HTMLChars]{\title} excerpt: '\begin{\note}\format[RemoveLatexCommands,HTMLChars]{\note}\end{\note}' -date: \format{\year}-\begin{\month}\format{\month}\end{\month}\begin{!month}\format{(01)}\end{!month}-\begin{\day}\format{\day}\end{\day}\begin{!day}\format{(01)}\end{!day} +date: \format{\year}-\begin{\month}\format{\month}\end{\month}\begin{!month}\format{\month}\end{!month}-\begin{\day}\format{\day}\end{\day}\begin{!day}\format{(01)}\end{!day} venue: '\format[RemoveLatexCommands,HTMLChars]{\journal}' slidesurl: '' -paperurl: '\begin{\url}\format[RemoveLatexCommands,HTMLChars]{\url}\end{\url} \begin{!url}\format{\doi}\end{!url}' +paperurl: '\begin{\url}\format[RemoveLatexCommands,HTMLChars]{\url}\end{\url}\begin{!url}\format{\doi}\end{!url}' bibtexurl: '' citation: '\format[HTMLChars]{\author}. (\format{\year}). ""\format[RemoveLatexCommands,HTMLChars]{\title}." \format[RemoveLatexCommands,HTMLChars]{\journal}.' --- From 8e76f570fbdd3ea52ea7ce73070d8d88a593e19c Mon Sep 17 00:00:00 2001 From: sadok Date: Wed, 5 Nov 2025 23:05:57 +0100 Subject: [PATCH 05/36] generalisation du layout en utilisant academicpages.layout --- .../jabref/logic/exporter/ExporterFactory.java | 2 +- .../academicpages/academicpages.article.layout | 14 +++++++------- .../layout/academicpages/academicpages.layout | 13 +++++++++++++ .../academicpages/academicpages.page.layout | 0 .../academicpages/academicpages.portfolio.layout | 0 .../academicpages/academicpages.post.layout | 0 .../academicpages.publication.layout | 1 - .../academicpages/academicpages.talk.layout | 15 --------------- .../academicpages/academicpages.teaching.layout | 0 9 files changed, 21 insertions(+), 24 deletions(-) create mode 100644 jablib/src/main/resources/resource/layout/academicpages/academicpages.layout delete mode 100644 jablib/src/main/resources/resource/layout/academicpages/academicpages.page.layout delete mode 100644 jablib/src/main/resources/resource/layout/academicpages/academicpages.portfolio.layout delete mode 100644 jablib/src/main/resources/resource/layout/academicpages/academicpages.post.layout delete mode 100644 jablib/src/main/resources/resource/layout/academicpages/academicpages.publication.layout delete mode 100644 jablib/src/main/resources/resource/layout/academicpages/academicpages.talk.layout delete mode 100644 jablib/src/main/resources/resource/layout/academicpages/academicpages.teaching.layout diff --git a/jablib/src/main/java/org/jabref/logic/exporter/ExporterFactory.java b/jablib/src/main/java/org/jabref/logic/exporter/ExporterFactory.java index 9e2454ecab2..3da162b34e3 100644 --- a/jablib/src/main/java/org/jabref/logic/exporter/ExporterFactory.java +++ b/jablib/src/main/java/org/jabref/logic/exporter/ExporterFactory.java @@ -54,7 +54,7 @@ public static ExporterFactory create(CliPreferences preferences) { exporters.add(new TemplateExporter("MIS Quarterly", "misq", "misq", "misq", StandardFileType.RTF, layoutPreferences, saveOrder)); exporters.add(new TemplateExporter("CSL YAML", "yaml", "yaml", null, StandardFileType.YAML, layoutPreferences, saveOrder, BlankLineBehaviour.DELETE_BLANKS)); exporters.add(new TemplateExporter("Hayagriva YAML", "hayagrivayaml", "hayagrivayaml", null, StandardFileType.YAML, layoutPreferences, saveOrder, BlankLineBehaviour.DELETE_BLANKS)); - exporters.add(new TemplateExporter(Localization.lang("Markdown academicpages"), "academicpages", "academicpages.article", "academicpages", StandardFileType.MARKDOWN, layoutPreferences, saveOrder)); + exporters.add(new TemplateExporter(Localization.lang("Markdown academicpages"), "academicpages", "academicpages", "academicpages", StandardFileType.MARKDOWN, layoutPreferences, saveOrder)); exporters.add(new OpenOfficeDocumentCreator()); exporters.add(new OpenDocumentSpreadsheetCreator()); exporters.add(new MSBibExporter()); diff --git a/jablib/src/main/resources/resource/layout/academicpages/academicpages.article.layout b/jablib/src/main/resources/resource/layout/academicpages/academicpages.article.layout index ccde8a2d241..3785da0c3a6 100644 --- a/jablib/src/main/resources/resource/layout/academicpages/academicpages.article.layout +++ b/jablib/src/main/resources/resource/layout/academicpages/academicpages.article.layout @@ -1,13 +1,13 @@ --- title: "\format[RemoveLatexCommands,HTMLChars]{\title}" collection: publications -category: article -permalink: /publication/\format{\year}-\begin{\month}\format{\month}\end{\month}\begin{!month}01\end{!month}-\begin{\day}\format{\day}\end{\day}\begin{!day}01\end{!day}-\format[RemoveLatexCommands,HTMLChars]{\title} -excerpt: '\begin{\note}\format[RemoveLatexCommands,HTMLChars]{\note}\end{\note}' -date: \format{\year}-\begin{\month}\format{\month}\end{\month}\begin{!month}\format{\month}\end{!month}-\begin{\day}\format{\day}\end{\day}\begin{!day}\format{(01)}\end{!day} +category: \format{\entrytype} +permalink: /publication/\format{\year}-\begin{month}\format{\month}\end{month}\begin{!month}01\end{!month}-\begin{day}\format{\day}\end{day}\begin{!day}01\end{!day}-"\format[RemoveLatexCommands,HTMLChars]{\title}" +excerpt: '\begin{note}\format[RemoveLatexCommands,HTMLChars]{\note}\end{note}' +date: \format{\year}-\begin{month}\format{\month}\end{month}\begin{!month}\format{\month}\end{!month}-\begin{day}\format{\day}\end{day}\begin{!day}\format{(01)}\end{!day} venue: '\format[RemoveLatexCommands,HTMLChars]{\journal}' -slidesurl: '' -paperurl: '\begin{\url}\format[RemoveLatexCommands,HTMLChars]{\url}\end{\url}\begin{!url}\format{\doi}\end{!url}' -bibtexurl: '' +slidesurl: '\begin{url}\format[RemoveLatexCommands,HTMLChars]{\url}\end{url}\begin{!url}\format{\doi}\end{!url}' +paperurl: '\begin{url}\format[RemoveLatexCommands,HTMLChars]{\url}\end{url}\begin{!url}\format{\doi}\end{!url}' +bibtexurl: '\begin{bibtexurl}\format{\bibtexurl}\end{bibtexurl}\begin{!url}\format{\doi}\end{!url}' citation: '\format[HTMLChars]{\author}. (\format{\year}). ""\format[RemoveLatexCommands,HTMLChars]{\title}." \format[RemoveLatexCommands,HTMLChars]{\journal}.' --- diff --git a/jablib/src/main/resources/resource/layout/academicpages/academicpages.layout b/jablib/src/main/resources/resource/layout/academicpages/academicpages.layout new file mode 100644 index 00000000000..3785da0c3a6 --- /dev/null +++ b/jablib/src/main/resources/resource/layout/academicpages/academicpages.layout @@ -0,0 +1,13 @@ +--- +title: "\format[RemoveLatexCommands,HTMLChars]{\title}" +collection: publications +category: \format{\entrytype} +permalink: /publication/\format{\year}-\begin{month}\format{\month}\end{month}\begin{!month}01\end{!month}-\begin{day}\format{\day}\end{day}\begin{!day}01\end{!day}-"\format[RemoveLatexCommands,HTMLChars]{\title}" +excerpt: '\begin{note}\format[RemoveLatexCommands,HTMLChars]{\note}\end{note}' +date: \format{\year}-\begin{month}\format{\month}\end{month}\begin{!month}\format{\month}\end{!month}-\begin{day}\format{\day}\end{day}\begin{!day}\format{(01)}\end{!day} +venue: '\format[RemoveLatexCommands,HTMLChars]{\journal}' +slidesurl: '\begin{url}\format[RemoveLatexCommands,HTMLChars]{\url}\end{url}\begin{!url}\format{\doi}\end{!url}' +paperurl: '\begin{url}\format[RemoveLatexCommands,HTMLChars]{\url}\end{url}\begin{!url}\format{\doi}\end{!url}' +bibtexurl: '\begin{bibtexurl}\format{\bibtexurl}\end{bibtexurl}\begin{!url}\format{\doi}\end{!url}' +citation: '\format[HTMLChars]{\author}. (\format{\year}). ""\format[RemoveLatexCommands,HTMLChars]{\title}." \format[RemoveLatexCommands,HTMLChars]{\journal}.' +--- diff --git a/jablib/src/main/resources/resource/layout/academicpages/academicpages.page.layout b/jablib/src/main/resources/resource/layout/academicpages/academicpages.page.layout deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/jablib/src/main/resources/resource/layout/academicpages/academicpages.portfolio.layout b/jablib/src/main/resources/resource/layout/academicpages/academicpages.portfolio.layout deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/jablib/src/main/resources/resource/layout/academicpages/academicpages.post.layout b/jablib/src/main/resources/resource/layout/academicpages/academicpages.post.layout deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/jablib/src/main/resources/resource/layout/academicpages/academicpages.publication.layout b/jablib/src/main/resources/resource/layout/academicpages/academicpages.publication.layout deleted file mode 100644 index 8b137891791..00000000000 --- a/jablib/src/main/resources/resource/layout/academicpages/academicpages.publication.layout +++ /dev/null @@ -1 +0,0 @@ - diff --git a/jablib/src/main/resources/resource/layout/academicpages/academicpages.talk.layout b/jablib/src/main/resources/resource/layout/academicpages/academicpages.talk.layout deleted file mode 100644 index 334957eb5ce..00000000000 --- a/jablib/src/main/resources/resource/layout/academicpages/academicpages.talk.layout +++ /dev/null @@ -1,15 +0,0 @@ ---- -title: "Paper Title Number 1" -collection: publications -category: manuscripts -permalink: /publication/2009-10-01-paper-title-number-1 -excerpt: 'This paper is about the number 1. The number 2 is left for future work.' -date: 2009-10-01 -venue: 'Journal 1' -slidesurl: 'https://academicpages.github.io/files/slides1.pdf' -paperurl: 'https://academicpages.github.io/files/paper1.pdf' -bibtexurl: 'https://academicpages.github.io/files/bibtex1.bib' -citation: 'Your Name, You. (2009). "Paper Title Number 1." Journal 1. 1(1).' ---- - -* \format[RemoveLatexCommands,HTMLChars]{\title}. \begin{journal}\format[RemoveLatexCommands,HTMLChars]{\journal}\end{journal}\begin{year} \format{\year}\end{year} diff --git a/jablib/src/main/resources/resource/layout/academicpages/academicpages.teaching.layout b/jablib/src/main/resources/resource/layout/academicpages/academicpages.teaching.layout deleted file mode 100644 index e69de29bb2d..00000000000 From 2799f1d5f9a773ddaa0c1115619b1d3174bc4171 Mon Sep 17 00:00:00 2001 From: sadok Date: Thu, 6 Nov 2025 17:43:13 +0100 Subject: [PATCH 06/36] =?UTF-8?q?am=C3=A9liorations=20au=20academicpages?= =?UTF-8?q?=20layout?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../academicpages/academicpages.article.layout | 13 ------------- .../layout/academicpages/academicpages.layout | 13 +++++++------ 2 files changed, 7 insertions(+), 19 deletions(-) delete mode 100644 jablib/src/main/resources/resource/layout/academicpages/academicpages.article.layout diff --git a/jablib/src/main/resources/resource/layout/academicpages/academicpages.article.layout b/jablib/src/main/resources/resource/layout/academicpages/academicpages.article.layout deleted file mode 100644 index 3785da0c3a6..00000000000 --- a/jablib/src/main/resources/resource/layout/academicpages/academicpages.article.layout +++ /dev/null @@ -1,13 +0,0 @@ ---- -title: "\format[RemoveLatexCommands,HTMLChars]{\title}" -collection: publications -category: \format{\entrytype} -permalink: /publication/\format{\year}-\begin{month}\format{\month}\end{month}\begin{!month}01\end{!month}-\begin{day}\format{\day}\end{day}\begin{!day}01\end{!day}-"\format[RemoveLatexCommands,HTMLChars]{\title}" -excerpt: '\begin{note}\format[RemoveLatexCommands,HTMLChars]{\note}\end{note}' -date: \format{\year}-\begin{month}\format{\month}\end{month}\begin{!month}\format{\month}\end{!month}-\begin{day}\format{\day}\end{day}\begin{!day}\format{(01)}\end{!day} -venue: '\format[RemoveLatexCommands,HTMLChars]{\journal}' -slidesurl: '\begin{url}\format[RemoveLatexCommands,HTMLChars]{\url}\end{url}\begin{!url}\format{\doi}\end{!url}' -paperurl: '\begin{url}\format[RemoveLatexCommands,HTMLChars]{\url}\end{url}\begin{!url}\format{\doi}\end{!url}' -bibtexurl: '\begin{bibtexurl}\format{\bibtexurl}\end{bibtexurl}\begin{!url}\format{\doi}\end{!url}' -citation: '\format[HTMLChars]{\author}. (\format{\year}). ""\format[RemoveLatexCommands,HTMLChars]{\title}." \format[RemoveLatexCommands,HTMLChars]{\journal}.' ---- diff --git a/jablib/src/main/resources/resource/layout/academicpages/academicpages.layout b/jablib/src/main/resources/resource/layout/academicpages/academicpages.layout index 3785da0c3a6..756cc4f892a 100644 --- a/jablib/src/main/resources/resource/layout/academicpages/academicpages.layout +++ b/jablib/src/main/resources/resource/layout/academicpages/academicpages.layout @@ -2,12 +2,13 @@ title: "\format[RemoveLatexCommands,HTMLChars]{\title}" collection: publications category: \format{\entrytype} -permalink: /publication/\format{\year}-\begin{month}\format{\month}\end{month}\begin{!month}01\end{!month}-\begin{day}\format{\day}\end{day}\begin{!day}01\end{!day}-"\format[RemoveLatexCommands,HTMLChars]{\title}" +permalink: /publication/\format{\year}-\begin{month}\format{\month}\end{month}\begin{!month}01\end{!month}-\begin{day}\format{\day}\end{day}\begin{!day}01\end{!day}-\format[RemoveLatexCommands,HTMLChars,Replace(\s,-)]{\title} excerpt: '\begin{note}\format[RemoveLatexCommands,HTMLChars]{\note}\end{note}' -date: \format{\year}-\begin{month}\format{\month}\end{month}\begin{!month}\format{\month}\end{!month}-\begin{day}\format{\day}\end{day}\begin{!day}\format{(01)}\end{!day} -venue: '\format[RemoveLatexCommands,HTMLChars]{\journal}' -slidesurl: '\begin{url}\format[RemoveLatexCommands,HTMLChars]{\url}\end{url}\begin{!url}\format{\doi}\end{!url}' -paperurl: '\begin{url}\format[RemoveLatexCommands,HTMLChars]{\url}\end{url}\begin{!url}\format{\doi}\end{!url}' -bibtexurl: '\begin{bibtexurl}\format{\bibtexurl}\end{bibtexurl}\begin{!url}\format{\doi}\end{!url}' +date: \format{\year}-\begin{month}\format{\month}\end{month}\begin{!month}01\end{!month}-\begin{day}\format{\day}\end{day}\begin{!day}01\end{!day} +venue: '\format[RemoveLatexCommands,HTMLChars]{\journal}\begin{!journal}Unknown\end{!journal}' +slidesurl: '\begin{file}\format[FileLink(pdf)]{\file}\end{file}\begin{!file}https://academicpages.github.io/files/[insert filename.pdf]\end{!file}' +paperurl: '\begin{file}\format[FileLink(pdf)]{\file}\end{file}\begin{!file}https://academicpages.github.io/files/[insert filename.pdf]\end{!file}' +bibtexurl: 'https://academicpages.github.io/files/[insert filename.bib]' citation: '\format[HTMLChars]{\author}. (\format{\year}). ""\format[RemoveLatexCommands,HTMLChars]{\title}." \format[RemoveLatexCommands,HTMLChars]{\journal}.' --- +\begin{abstract}\format{\abstract}\end{abstract} From be96c94a687a8e30476043be83c881c95d14a23d Mon Sep 17 00:00:00 2001 From: sadok Date: Tue, 25 Nov 2025 22:49:14 +0100 Subject: [PATCH 07/36] ajout d'un custom formatter to help with academic layout --- .../java/org/jabref/logic/layout/LayoutEntry.java | 3 +++ .../logic/layout/format/NumberMonthFormatter.java | 15 +++++++++++++++ .../layout/academicpages/academicpages.layout | 8 ++++---- 3 files changed, 22 insertions(+), 4 deletions(-) create mode 100644 jablib/src/main/java/org/jabref/logic/layout/format/NumberMonthFormatter.java diff --git a/jablib/src/main/java/org/jabref/logic/layout/LayoutEntry.java b/jablib/src/main/java/org/jabref/logic/layout/LayoutEntry.java index e2df268311d..cf838143b6f 100644 --- a/jablib/src/main/java/org/jabref/logic/layout/LayoutEntry.java +++ b/jablib/src/main/java/org/jabref/logic/layout/LayoutEntry.java @@ -66,6 +66,7 @@ import org.jabref.logic.layout.format.NonSpaceWhitespaceRemover; import org.jabref.logic.layout.format.NotFoundFormatter; import org.jabref.logic.layout.format.Number; +import org.jabref.logic.layout.format.NumberMonthFormatter; import org.jabref.logic.layout.format.Ordinal; import org.jabref.logic.layout.format.RTFChars; import org.jabref.logic.layout.format.RemoveBrackets; @@ -565,6 +566,8 @@ private LayoutFormatter getLayoutFormatterByName(String name) { new ReplaceWithEscapedDoubleQuotes(); case "HayagrivaType" -> new HayagrivaType(); + case "NumberMonth" -> + new NumberMonthFormatter(); default -> null; }; diff --git a/jablib/src/main/java/org/jabref/logic/layout/format/NumberMonthFormatter.java b/jablib/src/main/java/org/jabref/logic/layout/format/NumberMonthFormatter.java new file mode 100644 index 00000000000..5f09600edf4 --- /dev/null +++ b/jablib/src/main/java/org/jabref/logic/layout/format/NumberMonthFormatter.java @@ -0,0 +1,15 @@ +package org.jabref.logic.layout.format; + +import java.util.Optional; + +import org.jabref.logic.layout.LayoutFormatter; +import org.jabref.model.entry.Month; + +public class NumberMonthFormatter implements LayoutFormatter { + + @Override + public String format(String fieldText) { + Optional month = Month.parse(fieldText); + return month.map(Month::getTwoDigitNumber).orElse("01"); + } +} diff --git a/jablib/src/main/resources/resource/layout/academicpages/academicpages.layout b/jablib/src/main/resources/resource/layout/academicpages/academicpages.layout index 756cc4f892a..990c90cb106 100644 --- a/jablib/src/main/resources/resource/layout/academicpages/academicpages.layout +++ b/jablib/src/main/resources/resource/layout/academicpages/academicpages.layout @@ -4,11 +4,11 @@ collection: publications category: \format{\entrytype} permalink: /publication/\format{\year}-\begin{month}\format{\month}\end{month}\begin{!month}01\end{!month}-\begin{day}\format{\day}\end{day}\begin{!day}01\end{!day}-\format[RemoveLatexCommands,HTMLChars,Replace(\s,-)]{\title} excerpt: '\begin{note}\format[RemoveLatexCommands,HTMLChars]{\note}\end{note}' -date: \format{\year}-\begin{month}\format{\month}\end{month}\begin{!month}01\end{!month}-\begin{day}\format{\day}\end{day}\begin{!day}01\end{!day} +date: \format{\year}-\begin{month}\format[NumberMonth]{\month}\end{month}\begin{!month}01\end{!month}-\begin{day}\format{\day}\end{day}\begin{!day}01\end{!day} venue: '\format[RemoveLatexCommands,HTMLChars]{\journal}\begin{!journal}Unknown\end{!journal}' -slidesurl: '\begin{file}\format[FileLink(pdf)]{\file}\end{file}\begin{!file}https://academicpages.github.io/files/[insert filename.pdf]\end{!file}' -paperurl: '\begin{file}\format[FileLink(pdf)]{\file}\end{file}\begin{!file}https://academicpages.github.io/files/[insert filename.pdf]\end{!file}' -bibtexurl: 'https://academicpages.github.io/files/[insert filename.bib]' +slidesurl: '\begin{file}\format[FileLink(pdf)]{\file}\end{file}\begin{!file}https://[insert username].github.io/files/[insert filename].pdf\end{!file}' +paperurl: '\begin{file}\format[FileLink(pdf)]{\file}\end{file}\begin{!file}https://[insert username].github.io/files/[insert filename].pdf\end{!file}' +bibtexurl: 'https://[insert username].github.io/files/[insert filename].bib' citation: '\format[HTMLChars]{\author}. (\format{\year}). ""\format[RemoveLatexCommands,HTMLChars]{\title}." \format[RemoveLatexCommands,HTMLChars]{\journal}.' --- \begin{abstract}\format{\abstract}\end{abstract} From 1421e98d097ce82a22a74f5c1967e23e826a7077 Mon Sep 17 00:00:00 2001 From: Lucie Desnoyers Date: Wed, 26 Nov 2025 12:07:29 +0100 Subject: [PATCH 08/36] AcademicPagesExporter --- .../logic/exporter/AcademicPagesExporter.java | 111 ++++++++++++++++++ .../logic/exporter/ExporterFactory.java | 2 + 2 files changed, 113 insertions(+) create mode 100644 jablib/src/main/java/org/jabref/logic/exporter/AcademicPagesExporter.java diff --git a/jablib/src/main/java/org/jabref/logic/exporter/AcademicPagesExporter.java b/jablib/src/main/java/org/jabref/logic/exporter/AcademicPagesExporter.java new file mode 100644 index 00000000000..a859ad664f6 --- /dev/null +++ b/jablib/src/main/java/org/jabref/logic/exporter/AcademicPagesExporter.java @@ -0,0 +1,111 @@ +package org.jabref.logic.exporter; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.Reader; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.nio.file.Paths; +import java.util.Map; + +import org.jabref.logic.bibtex.FieldPreferences; +import org.jabref.logic.journals.JournalAbbreviationLoader; +import org.jabref.logic.journals.JournalAbbreviationRepository; +import org.jabref.logic.layout.Layout; +import org.jabref.logic.layout.LayoutFormatterPreferences; +import org.jabref.logic.layout.LayoutHelper; +import org.jabref.logic.layout.format.Number; +import org.jabref.logic.os.OS; +import org.jabref.logic.util.FileType; +import org.jabref.logic.util.StandardFileType; +import org.jabref.model.database.BibDatabaseContext; +import org.jabref.model.database.BibDatabaseMode; +import org.jabref.model.entry.BibEntry; +import org.jabref.model.entry.BibEntryTypesManager; +import org.jabref.model.entry.types.EntryType; +import org.jabref.model.metadata.SaveOrder; +import org.jabref.model.metadata.SelfContainedSaveOrder; + +import org.jspecify.annotations.NonNull; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * A custom exporter to write multiple bib entries as AcademicPages Markdown format. + */ +public class AcademicPagesExporter extends Exporter { + private static final String BLANK_LINE_PATTERN = "\\r\\n|\\n"; + private static final String LAYOUT_PREFIX = "/resource/layout/"; + private static final String LAYOUT_EXTENSION = ".layout"; + private static final String FORMATTERS_EXTENSION = ".formatters"; + private static final String BEGIN_INFIX = ".begin"; + private static final String END_INFIX = ".end"; + + private static final Logger LOGGER = LoggerFactory.getLogger(TemplateExporter.class); + + private final String lfFileName; + private final String directory; + private final LayoutFormatterPreferences layoutPreferences; + private final SelfContainedSaveOrder saveOrder; + private boolean customExport; + private List entries; + private TemplateExporter academicPagesTemplate; + + /** + * Initialize another export format based on templates stored in dir with layoutFile lfFilename. + * + */ + public AcademicPagesExporter(LayoutFormatterPreferences layoutPreferences, SelfContainedSaveOrder saveOrder) { + super("academicpages", "academicpages", StandardFileType.MARKDOWN); + this.lfFileName = "academicpages"; + this.directory = "academicpages"; + this.layoutPreferences = layoutPreferences; + this.saveOrder = saveOrder; + String consoleName = "academicpages"; + this.academicPagesTemplate = new TemplateExporter("academicpages", consoleName, lfFileName, directory, StandardFileType.MARKDOWN, layoutPreferences, saveOrder); + } + + @Override + public void export(@NonNull final BibDatabaseContext databaseContext, + final Path exportDirectory, + @NonNull List entries) throws SaveException { + export(databaseContext, exportDirectory, entries, List.of(), JournalAbbreviationLoader.loadBuiltInRepository()); + } + + /** + * The method that performs the export of all entries by iterating on the entries. + * + * @param databaseContext the database to export from + * @param exportDirectory the directory to write to + * @param entries a list containing all entries that should be exported + * @param abbreviationRepository the built-in repository + * @throws SaveException Exception thrown if saving goes wrong + */ + @Override + public void export(@NonNull final BibDatabaseContext databaseContext, + final Path exportDirectory, + @NonNull List entries, + List fileDirForDataBase, + JournalAbbreviationRepository abbreviationRepository) throws SaveException { + if (entries.isEmpty()) { // Only export if entries exist + return; + } + try { + Integer iterator = 1; + for (BibEntry entry : entries) { + Path path = Paths.get(exportDirectory.toString(), iterator.toString()); + iterator += 1; + academicPagesTemplate.export(databaseContext, path, entries, fileDirForDataBase, abbreviationRepository); + } + } catch (IOException e) { + return; + } + } +} diff --git a/jablib/src/main/java/org/jabref/logic/exporter/ExporterFactory.java b/jablib/src/main/java/org/jabref/logic/exporter/ExporterFactory.java index 3da162b34e3..64d26595642 100644 --- a/jablib/src/main/java/org/jabref/logic/exporter/ExporterFactory.java +++ b/jablib/src/main/java/org/jabref/logic/exporter/ExporterFactory.java @@ -12,6 +12,7 @@ import org.jabref.logic.util.StandardFileType; import org.jabref.logic.xmp.XmpPreferences; import org.jabref.model.database.BibDatabaseMode; +import org.jabref.model.entry.BibEntry; import org.jabref.model.metadata.SelfContainedSaveOrder; import org.jspecify.annotations.NonNull; @@ -64,6 +65,7 @@ public static ExporterFactory create(CliPreferences preferences) { exporters.add(new EmbeddedBibFilePdfExporter(bibDatabaseMode, preferences.getCustomEntryTypesRepository(), fieldPreferences)); exporters.add(new CffExporter()); exporters.add(new EndnoteXmlExporter(preferences.getBibEntryPreferences())); + exporters.add(new AcademicPagesExporter(layoutPreferences, saveOrder)); // Now add custom export formats exporters.addAll(customFormats); From e4a987cfd8e65cb6933cd86578db3279ee1211c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alo=C3=AFs=20VINCENT?= Date: Fri, 28 Nov 2025 15:32:18 +0100 Subject: [PATCH 09/36] test: add AcademicPagesExporter tests --- .../exporter/AcademicPagesExporterTest.java | 136 ++++++++++++++++++ 1 file changed, 136 insertions(+) create mode 100644 jablib/src/test/java/org/jabref/logic/exporter/AcademicPagesExporterTest.java diff --git a/jablib/src/test/java/org/jabref/logic/exporter/AcademicPagesExporterTest.java b/jablib/src/test/java/org/jabref/logic/exporter/AcademicPagesExporterTest.java new file mode 100644 index 00000000000..72301038753 --- /dev/null +++ b/jablib/src/test/java/org/jabref/logic/exporter/AcademicPagesExporterTest.java @@ -0,0 +1,136 @@ +package org.jabref.logic.exporter; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.List; + +import org.jabref.logic.layout.LayoutFormatterPreferences; +import org.jabref.model.database.BibDatabaseContext; +import org.jabref.model.entry.BibEntry; +import org.jabref.model.entry.field.StandardField; +import org.jabref.model.entry.types.StandardEntryType; +import org.jabref.model.metadata.SaveOrder; +import org.jabref.model.metadata.SelfContainedSaveOrder; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; +import org.mockito.Answers; + +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.Mockito.mock; + +class AcademicPagesExporterTest { + + private AcademicPagesExporter exporter; + private BibDatabaseContext databaseContext; + + @BeforeEach + void setUp() { + exporter = new AcademicPagesExporter( + mock(LayoutFormatterPreferences.class, Answers.RETURNS_DEEP_STUBS), + new SelfContainedSaveOrder(SaveOrder.OrderType.SPECIFIED, List.of())); + databaseContext = new BibDatabaseContext(); + } + + @Test + void exportArticleWithFullDateAndRequiredFieldsGeneratesCorrectFileNameAndContent(@TempDir Path tempDir) throws Exception { + BibEntry entry = new BibEntry(StandardEntryType.Article) + .withCitationKey("testKey") + .withField(StandardField.TITLE, "Test Title") + .withField(StandardField.AUTHOR, "Test Author") + .withField(StandardField.YEAR, "2023") + .withField(StandardField.MONTH, "05") + .withField(StandardField.DAY, "12") + .withField(StandardField.JOURNAL, "Test Journal"); + + exporter.export(databaseContext, tempDir, List.of(entry)); + + // Verify file name follows pattern: YYYY-MM-DD-title.md + Path expectedFile = tempDir.resolve("2023-05-12-test-title.md"); + assertTrue(Files.exists(expectedFile)); + + String content = Files.readString(expectedFile); + + // Verify YAML front matter fields + assertTrue(content.contains("title: \"Test Title\"")); + assertTrue(content.contains("date: 2023-05-12")); + assertTrue(content.contains("venue: 'Test Journal'")); + assertTrue(content.contains("citation: 'Test Author (2023). \"Test Title.\" Test Journal.'")); + } + + @Test + void exportArticleWithMissingMonthAndDayDefaultsToJanuaryFirst(@TempDir Path tempDir) throws Exception { + BibEntry entry = new BibEntry(StandardEntryType.Article) + .withCitationKey("testKey") + .withField(StandardField.TITLE, "No Date") + .withField(StandardField.YEAR, "2023"); + + exporter.export(databaseContext, tempDir, List.of(entry)); + + // Expect default date 2023-01-01 + Path expectedFile = tempDir.resolve("2023-01-01-no-date.md"); + assertTrue(Files.exists(expectedFile)); + + String content = Files.readString(expectedFile); + assertTrue(content.contains("date: 2023-01-01")); + } + + @Test + void exportArticleWithAbstractAppendsAbstractAfterYamlFrontMatter(@TempDir Path tempDir) throws Exception { + BibEntry entry = new BibEntry(StandardEntryType.Article) + .withCitationKey("testKey") + .withField(StandardField.TITLE, "Abstract Paper") + .withField(StandardField.YEAR, "2023") + .withField(StandardField.ABSTRACT, "This is a test abstract."); + + exporter.export(databaseContext, tempDir, List.of(entry)); + + Path expectedFile = tempDir.resolve("2023-01-01-abstract-paper.md"); + assertTrue(Files.exists(expectedFile)); + + String content = Files.readString(expectedFile); + + // Abstract should be outside the YAML block (after the second '---') + assertTrue(content.contains("---")); + assertTrue(content.endsWith("\nThis is a test abstract.\n")); + } + + @Test + void exportMultipleEntriesGeneratesMultipleIndividualMarkdownFiles(@TempDir Path tempDir) throws Exception { + BibEntry entry1 = new BibEntry(StandardEntryType.Article) + .withCitationKey("key1") + .withField(StandardField.TITLE, "Paper One") + .withField(StandardField.YEAR, "2023"); + + BibEntry entry2 = new BibEntry(StandardEntryType.Book) + .withCitationKey("key2") + .withField(StandardField.TITLE, "Book Two") + .withField(StandardField.YEAR, "2022"); + + exporter.export(databaseContext, tempDir, List.of(entry1, entry2)); + + // Verify both files exist + assertTrue(Files.exists(tempDir.resolve("2023-01-01-paper-one.md"))); + assertTrue(Files.exists(tempDir.resolve("2022-01-01-book-two.md"))); + } + + @Test + void exportInProceedingsWithBooktitleUsesBooktitleAsVenueAlias(@TempDir Path tempDir) throws Exception { + BibEntry entry = new BibEntry(StandardEntryType.InProceedings) + .withCitationKey("testKey") + .withField(StandardField.TITLE, "Conference Paper") + .withField(StandardField.YEAR, "2023") + .withField(StandardField.BOOKTITLE, "Conference Proceedings"); + + exporter.export(databaseContext, tempDir, List.of(entry)); + + Path expectedFile = tempDir.resolve("2023-01-01-conference-paper.md"); + assertTrue(Files.exists(expectedFile)); + + String content = Files.readString(expectedFile); + + // 'venue' should be populated from 'booktitle' since 'journal' is missing + assertTrue(content.contains("venue: 'Conference Proceedings'")); + } +} From df7aa05c3df069a921bf5f4d43cda2796a63bb45 Mon Sep 17 00:00:00 2001 From: Lucie Desnoyers Date: Sat, 29 Nov 2025 10:43:16 +0100 Subject: [PATCH 10/36] Delete unecessary imports --- .../logic/exporter/AcademicPagesExporter.java | 24 ++----------------- 1 file changed, 2 insertions(+), 22 deletions(-) diff --git a/jablib/src/main/java/org/jabref/logic/exporter/AcademicPagesExporter.java b/jablib/src/main/java/org/jabref/logic/exporter/AcademicPagesExporter.java index a859ad664f6..2312382f288 100644 --- a/jablib/src/main/java/org/jabref/logic/exporter/AcademicPagesExporter.java +++ b/jablib/src/main/java/org/jabref/logic/exporter/AcademicPagesExporter.java @@ -1,36 +1,16 @@ package org.jabref.logic.exporter; -import java.io.BufferedReader; import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.Reader; -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; import java.nio.file.Path; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; import java.nio.file.Paths; -import java.util.Map; +import java.util.List; -import org.jabref.logic.bibtex.FieldPreferences; import org.jabref.logic.journals.JournalAbbreviationLoader; import org.jabref.logic.journals.JournalAbbreviationRepository; -import org.jabref.logic.layout.Layout; import org.jabref.logic.layout.LayoutFormatterPreferences; -import org.jabref.logic.layout.LayoutHelper; -import org.jabref.logic.layout.format.Number; -import org.jabref.logic.os.OS; -import org.jabref.logic.util.FileType; import org.jabref.logic.util.StandardFileType; import org.jabref.model.database.BibDatabaseContext; -import org.jabref.model.database.BibDatabaseMode; import org.jabref.model.entry.BibEntry; -import org.jabref.model.entry.BibEntryTypesManager; -import org.jabref.model.entry.types.EntryType; -import org.jabref.model.metadata.SaveOrder; import org.jabref.model.metadata.SelfContainedSaveOrder; import org.jspecify.annotations.NonNull; @@ -56,7 +36,7 @@ public class AcademicPagesExporter extends Exporter { private final SelfContainedSaveOrder saveOrder; private boolean customExport; private List entries; - private TemplateExporter academicPagesTemplate; + private final TemplateExporter academicPagesTemplate; /** * Initialize another export format based on templates stored in dir with layoutFile lfFilename. From 9b12666fe165aa2a30c486adc4a124af284a2e7f Mon Sep 17 00:00:00 2001 From: Lucie Desnoyers Date: Sat, 29 Nov 2025 11:47:40 +0100 Subject: [PATCH 11/36] Changelog --- CHANGELOG.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 861471f2d69..f3233aeb8dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,10 +17,10 @@ Note that this project **does not** adhere to [Semantic Versioning](https://semv ### Removed -## [6.0-alpha.3] – 2025-10-30 +## [6.0-alpha.3] – 2025-11-29 ### Added - +- We added another custom Exporter "AcademciPagesExporter" and a new layout academicpages.layout as well as the corresponding line in ExporterFactory.java. [#12727](...) - We added an initial [cite as you write](https://retorque.re/zotero-better-bibtex/citing/cayw/) ("CAYW") endpoint. [#13187](https://github.com/JabRef/jabref/issues/13187) - We added a field for the latest ICORE conference ranking lookup on the General Tab. [#13476](https://github.com/JabRef/jabref/issues/13476) - We added the option to enable the language server in the preferences. [#13697](https://github.com/JabRef/jabref/pull/13697) @@ -82,7 +82,6 @@ Note that this project **does not** adhere to [Semantic Versioning](https://semv - We added "Bibliography Heading" to the available CSL bibliography header formats in the LibreOffice integration. [#13049](https://github.com/JabRef/jabref/issues/13049) ### Changed - - We merged the 'New Entry', 'Import by ID', and 'New Entry from Plain Text' tools into a single 'Create New Entry' tool. [#8808](https://github.com/JabRef/jabref/issues/8808) - We moved all sorting options into a dedicated “Sort” sub-menu in the Groups menu. ([#14017](https://github.com/JabRef/jabref/issues/14017)) - We merged `Citation information` and `Citation relations` into a singular tab. [#13618](https://github.com/JabRef/jabref/issues/13618) From f588da418fc028637816aff221f51e63071c43e4 Mon Sep 17 00:00:00 2001 From: Lucie Desnoyers Date: Sat, 29 Nov 2025 12:00:04 +0100 Subject: [PATCH 12/36] Changed CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f3233aeb8dd..9549b59d34e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,7 +20,7 @@ Note that this project **does not** adhere to [Semantic Versioning](https://semv ## [6.0-alpha.3] – 2025-11-29 ### Added -- We added another custom Exporter "AcademciPagesExporter" and a new layout academicpages.layout as well as the corresponding line in ExporterFactory.java. [#12727](...) +- We added another custom Exporter 'AcademicPagesExporter.java' and a new layout 'academicpages.layout' as well as the corresponding line in 'ExporterFactory.java'. [#12727](...) - We added an initial [cite as you write](https://retorque.re/zotero-better-bibtex/citing/cayw/) ("CAYW") endpoint. [#13187](https://github.com/JabRef/jabref/issues/13187) - We added a field for the latest ICORE conference ranking lookup on the General Tab. [#13476](https://github.com/JabRef/jabref/issues/13476) - We added the option to enable the language server in the preferences. [#13697](https://github.com/JabRef/jabref/pull/13697) From de65527af0ac2794b25c870d18f1db91a090f7a9 Mon Sep 17 00:00:00 2001 From: Lucie Desnoyers Date: Sat, 29 Nov 2025 12:04:28 +0100 Subject: [PATCH 13/36] trying to fix the CHANGELOG.md --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9549b59d34e..72aa0fdf8ab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,7 +20,7 @@ Note that this project **does not** adhere to [Semantic Versioning](https://semv ## [6.0-alpha.3] – 2025-11-29 ### Added -- We added another custom Exporter 'AcademicPagesExporter.java' and a new layout 'academicpages.layout' as well as the corresponding line in 'ExporterFactory.java'. [#12727](...) +- We added another custom Exporter AcademicPagesExporter and a new layout as well as the corresponding line in ExporterFactory. [#12727](...) - We added an initial [cite as you write](https://retorque.re/zotero-better-bibtex/citing/cayw/) ("CAYW") endpoint. [#13187](https://github.com/JabRef/jabref/issues/13187) - We added a field for the latest ICORE conference ranking lookup on the General Tab. [#13476](https://github.com/JabRef/jabref/issues/13476) - We added the option to enable the language server in the preferences. [#13697](https://github.com/JabRef/jabref/pull/13697) From 2d8afcfd93522210cab1bab5a67586e5d83c2ba7 Mon Sep 17 00:00:00 2001 From: Lucie Desnoyers Date: Sat, 29 Nov 2025 12:08:20 +0100 Subject: [PATCH 14/36] Adding blankspace in CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 72aa0fdf8ab..8bc700e9a6f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,6 +20,7 @@ Note that this project **does not** adhere to [Semantic Versioning](https://semv ## [6.0-alpha.3] – 2025-11-29 ### Added + - We added another custom Exporter AcademicPagesExporter and a new layout as well as the corresponding line in ExporterFactory. [#12727](...) - We added an initial [cite as you write](https://retorque.re/zotero-better-bibtex/citing/cayw/) ("CAYW") endpoint. [#13187](https://github.com/JabRef/jabref/issues/13187) - We added a field for the latest ICORE conference ranking lookup on the General Tab. [#13476](https://github.com/JabRef/jabref/issues/13476) @@ -82,6 +83,7 @@ Note that this project **does not** adhere to [Semantic Versioning](https://semv - We added "Bibliography Heading" to the available CSL bibliography header formats in the LibreOffice integration. [#13049](https://github.com/JabRef/jabref/issues/13049) ### Changed + - We merged the 'New Entry', 'Import by ID', and 'New Entry from Plain Text' tools into a single 'Create New Entry' tool. [#8808](https://github.com/JabRef/jabref/issues/8808) - We moved all sorting options into a dedicated “Sort” sub-menu in the Groups menu. ([#14017](https://github.com/JabRef/jabref/issues/14017)) - We merged `Citation information` and `Citation relations` into a singular tab. [#13618](https://github.com/JabRef/jabref/issues/13618) From 4ea372da8e18849ee441f9be1153405158e2a0d2 Mon Sep 17 00:00:00 2001 From: sadok Date: Sun, 30 Nov 2025 00:05:35 +0100 Subject: [PATCH 15/36] =?UTF-8?q?Correction=20du=20nouveau=20exporter=20+?= =?UTF-8?q?=20Coh=C3=A9rence=20des=20noms=20des=20fichiers=20produits=20av?= =?UTF-8?q?ec=20le=20format=20exig=C3=A9=20de=20academic=20pages?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../logic/exporter/AcademicPagesExporter.java | 63 +++++++++++-------- .../logic/exporter/ExporterFactory.java | 2 - .../org/jabref/logic/layout/LayoutEntry.java | 3 + .../layout/format/NumberMonthFormatter.java | 3 + .../logic/layout/format/SafeFileName.java | 14 +++++ .../layout/academicpages/academicpages.layout | 2 +- 6 files changed, 57 insertions(+), 30 deletions(-) create mode 100644 jablib/src/main/java/org/jabref/logic/layout/format/SafeFileName.java diff --git a/jablib/src/main/java/org/jabref/logic/exporter/AcademicPagesExporter.java b/jablib/src/main/java/org/jabref/logic/exporter/AcademicPagesExporter.java index a859ad664f6..0e7db8adfca 100644 --- a/jablib/src/main/java/org/jabref/logic/exporter/AcademicPagesExporter.java +++ b/jablib/src/main/java/org/jabref/logic/exporter/AcademicPagesExporter.java @@ -1,36 +1,22 @@ package org.jabref.logic.exporter; -import java.io.BufferedReader; import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.Reader; -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import java.nio.file.Paths; -import java.util.Map; -import org.jabref.logic.bibtex.FieldPreferences; import org.jabref.logic.journals.JournalAbbreviationLoader; import org.jabref.logic.journals.JournalAbbreviationRepository; -import org.jabref.logic.layout.Layout; import org.jabref.logic.layout.LayoutFormatterPreferences; -import org.jabref.logic.layout.LayoutHelper; -import org.jabref.logic.layout.format.Number; -import org.jabref.logic.os.OS; -import org.jabref.logic.util.FileType; +import org.jabref.logic.layout.format.HTMLChars; +import org.jabref.logic.layout.format.RemoveLatexCommandsFormatter; +import org.jabref.logic.layout.format.Replace; +import org.jabref.logic.layout.format.SafeFileName; import org.jabref.logic.util.StandardFileType; +import org.jabref.logic.util.io.FileUtil; import org.jabref.model.database.BibDatabaseContext; -import org.jabref.model.database.BibDatabaseMode; import org.jabref.model.entry.BibEntry; -import org.jabref.model.entry.BibEntryTypesManager; -import org.jabref.model.entry.types.EntryType; -import org.jabref.model.metadata.SaveOrder; import org.jabref.model.metadata.SelfContainedSaveOrder; import org.jspecify.annotations.NonNull; @@ -63,7 +49,7 @@ public class AcademicPagesExporter extends Exporter { * */ public AcademicPagesExporter(LayoutFormatterPreferences layoutPreferences, SelfContainedSaveOrder saveOrder) { - super("academicpages", "academicpages", StandardFileType.MARKDOWN); + super("academicpages", "academic pages markdowns", StandardFileType.MARKDOWN); this.lfFileName = "academicpages"; this.directory = "academicpages"; this.layoutPreferences = layoutPreferences; @@ -83,14 +69,14 @@ public void export(@NonNull final BibDatabaseContext databaseContext, * The method that performs the export of all entries by iterating on the entries. * * @param databaseContext the database to export from - * @param exportDirectory the directory to write to + * @param file the directory to write to * @param entries a list containing all entries that should be exported * @param abbreviationRepository the built-in repository * @throws SaveException Exception thrown if saving goes wrong */ @Override public void export(@NonNull final BibDatabaseContext databaseContext, - final Path exportDirectory, + final Path file, @NonNull List entries, List fileDirForDataBase, JournalAbbreviationRepository abbreviationRepository) throws SaveException { @@ -98,14 +84,37 @@ public void export(@NonNull final BibDatabaseContext databaseContext, return; } try { - Integer iterator = 1; + // convert what the ExportCommand gives as a file parameter to a directory + Path baseDir = file; + String exportDirectoryString = FileUtil.getBaseName(file); + Path exportDirectory = baseDir.getParent().resolve(exportDirectoryString); + + // Ensure the directory exists. This is important: AtomicFileWriter will fail if parent dirs are missing. + Files.createDirectories(exportDirectory); + for (BibEntry entry : entries) { - Path path = Paths.get(exportDirectory.toString(), iterator.toString()); - iterator += 1; - academicPagesTemplate.export(databaseContext, path, entries, fileDirForDataBase, abbreviationRepository); + if (entry.getType() == null) { + LOGGER.warn("Skipping entry with no type: {}", entry); + continue; + } + //formatting the title of each entry to match the file names format demanded by academic pages (applying the same formatters applied to the title in the academicpages.layout) + Replace replace_formatter = new Replace(); + replace_formatter.setArgument(" ,-"); + RemoveLatexCommandsFormatter commands_formatter = new RemoveLatexCommandsFormatter(); + HTMLChars html_formatter = new HTMLChars(); + String title = entry.getTitle().get(); + String formatted_title = commands_formatter.format(html_formatter.format(replace_formatter.format(title))); + SafeFileName safe_formatter = new SafeFileName(); // added custom formatter to remove all characters that are not allowed in filenames + String safe_title = safe_formatter.format(formatted_title); + + Path path = exportDirectory.resolve(safe_title + ".md"); + + List individual_entry = new ArrayList(); + individual_entry.add(entry); + academicPagesTemplate.export(databaseContext, path, individual_entry, fileDirForDataBase, abbreviationRepository); } } catch (IOException e) { - return; + throw new SaveException("could not export"); } } } diff --git a/jablib/src/main/java/org/jabref/logic/exporter/ExporterFactory.java b/jablib/src/main/java/org/jabref/logic/exporter/ExporterFactory.java index 64d26595642..820a3d063e1 100644 --- a/jablib/src/main/java/org/jabref/logic/exporter/ExporterFactory.java +++ b/jablib/src/main/java/org/jabref/logic/exporter/ExporterFactory.java @@ -12,7 +12,6 @@ import org.jabref.logic.util.StandardFileType; import org.jabref.logic.xmp.XmpPreferences; import org.jabref.model.database.BibDatabaseMode; -import org.jabref.model.entry.BibEntry; import org.jabref.model.metadata.SelfContainedSaveOrder; import org.jspecify.annotations.NonNull; @@ -55,7 +54,6 @@ public static ExporterFactory create(CliPreferences preferences) { exporters.add(new TemplateExporter("MIS Quarterly", "misq", "misq", "misq", StandardFileType.RTF, layoutPreferences, saveOrder)); exporters.add(new TemplateExporter("CSL YAML", "yaml", "yaml", null, StandardFileType.YAML, layoutPreferences, saveOrder, BlankLineBehaviour.DELETE_BLANKS)); exporters.add(new TemplateExporter("Hayagriva YAML", "hayagrivayaml", "hayagrivayaml", null, StandardFileType.YAML, layoutPreferences, saveOrder, BlankLineBehaviour.DELETE_BLANKS)); - exporters.add(new TemplateExporter(Localization.lang("Markdown academicpages"), "academicpages", "academicpages", "academicpages", StandardFileType.MARKDOWN, layoutPreferences, saveOrder)); exporters.add(new OpenOfficeDocumentCreator()); exporters.add(new OpenDocumentSpreadsheetCreator()); exporters.add(new MSBibExporter()); diff --git a/jablib/src/main/java/org/jabref/logic/layout/LayoutEntry.java b/jablib/src/main/java/org/jabref/logic/layout/LayoutEntry.java index cf838143b6f..082c7901d6e 100644 --- a/jablib/src/main/java/org/jabref/logic/layout/LayoutEntry.java +++ b/jablib/src/main/java/org/jabref/logic/layout/LayoutEntry.java @@ -78,6 +78,7 @@ import org.jabref.logic.layout.format.RisAuthors; import org.jabref.logic.layout.format.RisKeywords; import org.jabref.logic.layout.format.RisMonth; +import org.jabref.logic.layout.format.SafeFileName; import org.jabref.logic.layout.format.ShortMonthFormatter; import org.jabref.logic.layout.format.ToLowerCase; import org.jabref.logic.layout.format.ToUpperCase; @@ -568,6 +569,8 @@ private LayoutFormatter getLayoutFormatterByName(String name) { new HayagrivaType(); case "NumberMonth" -> new NumberMonthFormatter(); + case "SafeFileName" -> + new SafeFileName(); default -> null; }; diff --git a/jablib/src/main/java/org/jabref/logic/layout/format/NumberMonthFormatter.java b/jablib/src/main/java/org/jabref/logic/layout/format/NumberMonthFormatter.java index 5f09600edf4..06d3a0e86eb 100644 --- a/jablib/src/main/java/org/jabref/logic/layout/format/NumberMonthFormatter.java +++ b/jablib/src/main/java/org/jabref/logic/layout/format/NumberMonthFormatter.java @@ -5,6 +5,9 @@ import org.jabref.logic.layout.LayoutFormatter; import org.jabref.model.entry.Month; +/** + * Convert the month name into the corresponding number and return 01 by default + */ public class NumberMonthFormatter implements LayoutFormatter { @Override diff --git a/jablib/src/main/java/org/jabref/logic/layout/format/SafeFileName.java b/jablib/src/main/java/org/jabref/logic/layout/format/SafeFileName.java new file mode 100644 index 00000000000..081b65e47c4 --- /dev/null +++ b/jablib/src/main/java/org/jabref/logic/layout/format/SafeFileName.java @@ -0,0 +1,14 @@ +package org.jabref.logic.layout.format; + +import org.jabref.logic.layout.LayoutFormatter; + +/** + * Remove all the characters that are not allowed by the OS in file names + */ +public class SafeFileName implements LayoutFormatter { + + @Override + public String format(String fieldText) { + return fieldText.replaceAll("[\\\\/:*?\"<>|]", ""); + } +} diff --git a/jablib/src/main/resources/resource/layout/academicpages/academicpages.layout b/jablib/src/main/resources/resource/layout/academicpages/academicpages.layout index 990c90cb106..8cb46cc21de 100644 --- a/jablib/src/main/resources/resource/layout/academicpages/academicpages.layout +++ b/jablib/src/main/resources/resource/layout/academicpages/academicpages.layout @@ -2,7 +2,7 @@ title: "\format[RemoveLatexCommands,HTMLChars]{\title}" collection: publications category: \format{\entrytype} -permalink: /publication/\format{\year}-\begin{month}\format{\month}\end{month}\begin{!month}01\end{!month}-\begin{day}\format{\day}\end{day}\begin{!day}01\end{!day}-\format[RemoveLatexCommands,HTMLChars,Replace(\s,-)]{\title} +permalink: /publication/\format[RemoveLatexCommands,HTMLChars,Replace(\s,-),SafeFileName]{\title} excerpt: '\begin{note}\format[RemoveLatexCommands,HTMLChars]{\note}\end{note}' date: \format{\year}-\begin{month}\format[NumberMonth]{\month}\end{month}\begin{!month}01\end{!month}-\begin{day}\format{\day}\end{day}\begin{!day}01\end{!day} venue: '\format[RemoveLatexCommands,HTMLChars]{\journal}\begin{!journal}Unknown\end{!journal}' From 9b8a86d0a60e942029b371ff923b6f9076175be1 Mon Sep 17 00:00:00 2001 From: Lucie Desnoyers Date: Mon, 1 Dec 2025 20:34:13 +0100 Subject: [PATCH 16/36] Reverted the date on the CHANGELOG.md and one change on AcademicPagesExporter.java --- CHANGELOG.md | 2 +- .../logic/exporter/AcademicPagesExporter.java | 26 +++++++++++-------- 2 files changed, 16 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8bc700e9a6f..f67354b70b8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,7 +17,7 @@ Note that this project **does not** adhere to [Semantic Versioning](https://semv ### Removed -## [6.0-alpha.3] – 2025-11-29 +## [6.0-alpha.3] – 2025-10-30 ### Added diff --git a/jablib/src/main/java/org/jabref/logic/exporter/AcademicPagesExporter.java b/jablib/src/main/java/org/jabref/logic/exporter/AcademicPagesExporter.java index 0e7db8adfca..7bd432cb4ba 100644 --- a/jablib/src/main/java/org/jabref/logic/exporter/AcademicPagesExporter.java +++ b/jablib/src/main/java/org/jabref/logic/exporter/AcademicPagesExporter.java @@ -19,6 +19,7 @@ import org.jabref.model.entry.BibEntry; import org.jabref.model.metadata.SelfContainedSaveOrder; +import org.jetbrains.annotations.NotNull; import org.jspecify.annotations.NonNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -97,17 +98,8 @@ public void export(@NonNull final BibDatabaseContext databaseContext, LOGGER.warn("Skipping entry with no type: {}", entry); continue; } - //formatting the title of each entry to match the file names format demanded by academic pages (applying the same formatters applied to the title in the academicpages.layout) - Replace replace_formatter = new Replace(); - replace_formatter.setArgument(" ,-"); - RemoveLatexCommandsFormatter commands_formatter = new RemoveLatexCommandsFormatter(); - HTMLChars html_formatter = new HTMLChars(); - String title = entry.getTitle().get(); - String formatted_title = commands_formatter.format(html_formatter.format(replace_formatter.format(title))); - SafeFileName safe_formatter = new SafeFileName(); // added custom formatter to remove all characters that are not allowed in filenames - String safe_title = safe_formatter.format(formatted_title); - - Path path = exportDirectory.resolve(safe_title + ".md"); + // formatting the title of each entry to match the file names format demanded by academic pages (applying the same formatters applied to the title in the academicpages.layout) + Path path = getPath(entry, exportDirectory); List individual_entry = new ArrayList(); individual_entry.add(entry); @@ -117,4 +109,16 @@ public void export(@NonNull final BibDatabaseContext databaseContext, throw new SaveException("could not export"); } } + + private static @NotNull Path getPath(BibEntry entry, Path exportDirectory) { + Replace replace_formatter = new Replace(); + replace_formatter.setArgument(" ,-"); + RemoveLatexCommandsFormatter commands_formatter = new RemoveLatexCommandsFormatter(); + HTMLChars html_formatter = new HTMLChars(); + String title = entry.getTitle().get(); + String formatted_title = commands_formatter.format(html_formatter.format(replace_formatter.format(title))); + SafeFileName safe_formatter = new SafeFileName(); // added custom formatter to remove all characters that are not allowed in filenames + String safe_title = safe_formatter.format(formatted_title); + return exportDirectory.resolve(safe_title + ".md"); + } } From 90873901682dbc1ee9308104ced6177352794bb9 Mon Sep 17 00:00:00 2001 From: Lucie Desnoyers Date: Mon, 1 Dec 2025 20:41:09 +0100 Subject: [PATCH 17/36] revert all changes to Changelog.md --- CHANGELOG.md | 1 - 1 file changed, 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f67354b70b8..861471f2d69 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,7 +21,6 @@ Note that this project **does not** adhere to [Semantic Versioning](https://semv ### Added -- We added another custom Exporter AcademicPagesExporter and a new layout as well as the corresponding line in ExporterFactory. [#12727](...) - We added an initial [cite as you write](https://retorque.re/zotero-better-bibtex/citing/cayw/) ("CAYW") endpoint. [#13187](https://github.com/JabRef/jabref/issues/13187) - We added a field for the latest ICORE conference ranking lookup on the General Tab. [#13476](https://github.com/JabRef/jabref/issues/13476) - We added the option to enable the language server in the preferences. [#13697](https://github.com/JabRef/jabref/pull/13697) From 655afe3f23fc04e1e401b4f23afad3cdc7b1a3d0 Mon Sep 17 00:00:00 2001 From: sadok Date: Tue, 2 Dec 2025 08:39:06 +0100 Subject: [PATCH 18/36] format correction for the file : LayoutEntry --- jablib/src/main/java/org/jabref/logic/layout/LayoutEntry.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/jablib/src/main/java/org/jabref/logic/layout/LayoutEntry.java b/jablib/src/main/java/org/jabref/logic/layout/LayoutEntry.java index 082c7901d6e..03ce96ed7d6 100644 --- a/jablib/src/main/java/org/jabref/logic/layout/LayoutEntry.java +++ b/jablib/src/main/java/org/jabref/logic/layout/LayoutEntry.java @@ -568,9 +568,9 @@ private LayoutFormatter getLayoutFormatterByName(String name) { case "HayagrivaType" -> new HayagrivaType(); case "NumberMonth" -> - new NumberMonthFormatter(); + new NumberMonthFormatter(); case "SafeFileName" -> - new SafeFileName(); + new SafeFileName(); default -> null; }; From 30e76267dbdb7dacb232fa2419a63da58e2c1f4c Mon Sep 17 00:00:00 2001 From: Lucie Desnoyers Date: Tue, 2 Dec 2025 09:29:02 +0100 Subject: [PATCH 19/36] trying to fix Open Rewrite problem --- .../java/org/jabref/logic/exporter/AcademicPagesExporter.java | 4 ++-- .../org/jabref/logic/exporter/AcademicPagesExporterTest.java | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/jablib/src/main/java/org/jabref/logic/exporter/AcademicPagesExporter.java b/jablib/src/main/java/org/jabref/logic/exporter/AcademicPagesExporter.java index 7bd432cb4ba..ac707a347e2 100644 --- a/jablib/src/main/java/org/jabref/logic/exporter/AcademicPagesExporter.java +++ b/jablib/src/main/java/org/jabref/logic/exporter/AcademicPagesExporter.java @@ -35,7 +35,7 @@ public class AcademicPagesExporter extends Exporter { private static final String BEGIN_INFIX = ".begin"; private static final String END_INFIX = ".end"; - private static final Logger LOGGER = LoggerFactory.getLogger(TemplateExporter.class); + private static final Logger LOGGER = LoggerFactory.getLogger(AcademicPagesExporter.class); private final String lfFileName; private final String directory; @@ -101,7 +101,7 @@ public void export(@NonNull final BibDatabaseContext databaseContext, // formatting the title of each entry to match the file names format demanded by academic pages (applying the same formatters applied to the title in the academicpages.layout) Path path = getPath(entry, exportDirectory); - List individual_entry = new ArrayList(); + List individual_entry = new ArrayList<>(); individual_entry.add(entry); academicPagesTemplate.export(databaseContext, path, individual_entry, fileDirForDataBase, abbreviationRepository); } diff --git a/jablib/src/test/java/org/jabref/logic/exporter/AcademicPagesExporterTest.java b/jablib/src/test/java/org/jabref/logic/exporter/AcademicPagesExporterTest.java index 72301038753..505abcd07f4 100644 --- a/jablib/src/test/java/org/jabref/logic/exporter/AcademicPagesExporterTest.java +++ b/jablib/src/test/java/org/jabref/logic/exporter/AcademicPagesExporterTest.java @@ -17,7 +17,7 @@ import org.junit.jupiter.api.io.TempDir; import org.mockito.Answers; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.jgitunit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.mock; class AcademicPagesExporterTest { From 6e07a52126799eb1de93b020581b610575e2d1e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alo=C3=AFs=20VINCENT?= Date: Tue, 2 Dec 2025 09:29:34 +0100 Subject: [PATCH 20/36] Refactor AcademicPagesExporterTest to use full content comparison --- .../exporter/AcademicPagesExporterTest.java | 189 +++++++++++++----- 1 file changed, 138 insertions(+), 51 deletions(-) diff --git a/jablib/src/test/java/org/jabref/logic/exporter/AcademicPagesExporterTest.java b/jablib/src/test/java/org/jabref/logic/exporter/AcademicPagesExporterTest.java index 72301038753..8844f838007 100644 --- a/jablib/src/test/java/org/jabref/logic/exporter/AcademicPagesExporterTest.java +++ b/jablib/src/test/java/org/jabref/logic/exporter/AcademicPagesExporterTest.java @@ -17,6 +17,7 @@ import org.junit.jupiter.api.io.TempDir; import org.mockito.Answers; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.mock; @@ -28,109 +29,195 @@ class AcademicPagesExporterTest { @BeforeEach void setUp() { exporter = new AcademicPagesExporter( - mock(LayoutFormatterPreferences.class, Answers.RETURNS_DEEP_STUBS), - new SelfContainedSaveOrder(SaveOrder.OrderType.SPECIFIED, List.of())); + mock(LayoutFormatterPreferences.class, Answers.RETURNS_DEEP_STUBS), + new SelfContainedSaveOrder(SaveOrder.OrderType.SPECIFIED, List.of())); databaseContext = new BibDatabaseContext(); } @Test void exportArticleWithFullDateAndRequiredFieldsGeneratesCorrectFileNameAndContent(@TempDir Path tempDir) throws Exception { BibEntry entry = new BibEntry(StandardEntryType.Article) - .withCitationKey("testKey") - .withField(StandardField.TITLE, "Test Title") - .withField(StandardField.AUTHOR, "Test Author") - .withField(StandardField.YEAR, "2023") - .withField(StandardField.MONTH, "05") - .withField(StandardField.DAY, "12") - .withField(StandardField.JOURNAL, "Test Journal"); + .withCitationKey("testKey") + .withField(StandardField.TITLE, "Test Title") + .withField(StandardField.AUTHOR, "Test Author") + .withField(StandardField.YEAR, "2023") + .withField(StandardField.MONTH, "05") + .withField(StandardField.DAY, "12") + .withField(StandardField.JOURNAL, "Test Journal"); exporter.export(databaseContext, tempDir, List.of(entry)); - // Verify file name follows pattern: YYYY-MM-DD-title.md - Path expectedFile = tempDir.resolve("2023-05-12-test-title.md"); + // Verify file name follows pattern: title.md (SafeFileName) + Path expectedFile = tempDir.resolve("Test-Title.md"); assertTrue(Files.exists(expectedFile)); - String content = Files.readString(expectedFile); - - // Verify YAML front matter fields - assertTrue(content.contains("title: \"Test Title\"")); - assertTrue(content.contains("date: 2023-05-12")); - assertTrue(content.contains("venue: 'Test Journal'")); - assertTrue(content.contains("citation: 'Test Author (2023). \"Test Title.\" Test Journal.'")); + List expected = List.of( + "---", + "title: \"Test Title\"", + "collection: publications", + "category: Article", + "permalink: /publication/Test-Title", + "excerpt: ''", + "date: 2023-05-12", + "venue: 'Test Journal'", + "slidesurl: 'https://[insert username].github.io/files/[insert filename].pdf'", + "paperurl: 'https://[insert username].github.io/files/[insert filename].pdf'", + "bibtexurl: 'https://[insert username].github.io/files/[insert filename].bib'", + "citation: 'Test Author. (2023). \""Test Title." Test Journal.'", + "---", + ""); + + assertEquals(expected, Files.readAllLines(expectedFile)); } @Test void exportArticleWithMissingMonthAndDayDefaultsToJanuaryFirst(@TempDir Path tempDir) throws Exception { BibEntry entry = new BibEntry(StandardEntryType.Article) - .withCitationKey("testKey") - .withField(StandardField.TITLE, "No Date") - .withField(StandardField.YEAR, "2023"); + .withCitationKey("testKey") + .withField(StandardField.TITLE, "No Date") + .withField(StandardField.YEAR, "2023"); exporter.export(databaseContext, tempDir, List.of(entry)); // Expect default date 2023-01-01 - Path expectedFile = tempDir.resolve("2023-01-01-no-date.md"); + Path expectedFile = tempDir.resolve("No-Date.md"); assertTrue(Files.exists(expectedFile)); - String content = Files.readString(expectedFile); - assertTrue(content.contains("date: 2023-01-01")); + List expected = List.of( + "---", + "title: \"No Date\"", + "collection: publications", + "category: Article", + "permalink: /publication/No-Date", + "excerpt: ''", + "date: 2023-01-01", + "venue: 'Unknown'", + "slidesurl: 'https://[insert username].github.io/files/[insert filename].pdf'", + "paperurl: 'https://[insert username].github.io/files/[insert filename].pdf'", + "bibtexurl: 'https://[insert username].github.io/files/[insert filename].bib'", + "citation: '. (2023). \""No Date." .'", + "---", + ""); + + assertEquals(expected, Files.readAllLines(expectedFile)); } @Test void exportArticleWithAbstractAppendsAbstractAfterYamlFrontMatter(@TempDir Path tempDir) throws Exception { BibEntry entry = new BibEntry(StandardEntryType.Article) - .withCitationKey("testKey") - .withField(StandardField.TITLE, "Abstract Paper") - .withField(StandardField.YEAR, "2023") - .withField(StandardField.ABSTRACT, "This is a test abstract."); + .withCitationKey("testKey") + .withField(StandardField.TITLE, "Abstract Paper") + .withField(StandardField.YEAR, "2023") + .withField(StandardField.ABSTRACT, "This is a test abstract."); exporter.export(databaseContext, tempDir, List.of(entry)); - Path expectedFile = tempDir.resolve("2023-01-01-abstract-paper.md"); + Path expectedFile = tempDir.resolve("Abstract-Paper.md"); assertTrue(Files.exists(expectedFile)); - String content = Files.readString(expectedFile); - - // Abstract should be outside the YAML block (after the second '---') - assertTrue(content.contains("---")); - assertTrue(content.endsWith("\nThis is a test abstract.\n")); + List expected = List.of( + "---", + "title: \"Abstract Paper\"", + "collection: publications", + "category: Article", + "permalink: /publication/Abstract-Paper", + "excerpt: ''", + "date: 2023-01-01", + "venue: 'Unknown'", + "slidesurl: 'https://[insert username].github.io/files/[insert filename].pdf'", + "paperurl: 'https://[insert username].github.io/files/[insert filename].pdf'", + "bibtexurl: 'https://[insert username].github.io/files/[insert filename].bib'", + "citation: '. (2023). \""Abstract Paper." .'", + "---", + "This is a test abstract."); + + assertEquals(expected, Files.readAllLines(expectedFile)); } @Test void exportMultipleEntriesGeneratesMultipleIndividualMarkdownFiles(@TempDir Path tempDir) throws Exception { BibEntry entry1 = new BibEntry(StandardEntryType.Article) - .withCitationKey("key1") - .withField(StandardField.TITLE, "Paper One") - .withField(StandardField.YEAR, "2023"); + .withCitationKey("key1") + .withField(StandardField.TITLE, "Paper One") + .withField(StandardField.YEAR, "2023"); BibEntry entry2 = new BibEntry(StandardEntryType.Book) - .withCitationKey("key2") - .withField(StandardField.TITLE, "Book Two") - .withField(StandardField.YEAR, "2022"); + .withCitationKey("key2") + .withField(StandardField.TITLE, "Book Two") + .withField(StandardField.YEAR, "2022"); exporter.export(databaseContext, tempDir, List.of(entry1, entry2)); // Verify both files exist - assertTrue(Files.exists(tempDir.resolve("2023-01-01-paper-one.md"))); - assertTrue(Files.exists(tempDir.resolve("2022-01-01-book-two.md"))); + Path file1 = tempDir.resolve("Paper-One.md"); + Path file2 = tempDir.resolve("Book-Two.md"); + assertTrue(Files.exists(file1)); + assertTrue(Files.exists(file2)); + + List expected1 = List.of( + "---", + "title: \"Paper One\"", + "collection: publications", + "category: Article", + "permalink: /publication/Paper-One", + "excerpt: ''", + "date: 2023-01-01", + "venue: 'Unknown'", + "slidesurl: 'https://[insert username].github.io/files/[insert filename].pdf'", + "paperurl: 'https://[insert username].github.io/files/[insert filename].pdf'", + "bibtexurl: 'https://[insert username].github.io/files/[insert filename].bib'", + "citation: '. (2023). \""Paper One." .'", + "---", + ""); + assertEquals(expected1, Files.readAllLines(file1)); + + List expected2 = List.of( + "---", + "title: \"Book Two\"", + "collection: publications", + "category: Book", + "permalink: /publication/Book-Two", + "excerpt: ''", + "date: 2022-01-01", + "venue: 'Unknown'", + "slidesurl: 'https://[insert username].github.io/files/[insert filename].pdf'", + "paperurl: 'https://[insert username].github.io/files/[insert filename].pdf'", + "bibtexurl: 'https://[insert username].github.io/files/[insert filename].bib'", + "citation: '. (2022). \""Book Two." .'", + "---", + ""); + assertEquals(expected2, Files.readAllLines(file2)); } @Test void exportInProceedingsWithBooktitleUsesBooktitleAsVenueAlias(@TempDir Path tempDir) throws Exception { BibEntry entry = new BibEntry(StandardEntryType.InProceedings) - .withCitationKey("testKey") - .withField(StandardField.TITLE, "Conference Paper") - .withField(StandardField.YEAR, "2023") - .withField(StandardField.BOOKTITLE, "Conference Proceedings"); + .withCitationKey("testKey") + .withField(StandardField.TITLE, "Conference Paper") + .withField(StandardField.YEAR, "2023") + .withField(StandardField.BOOKTITLE, "Conference Proceedings"); exporter.export(databaseContext, tempDir, List.of(entry)); - Path expectedFile = tempDir.resolve("2023-01-01-conference-paper.md"); + Path expectedFile = tempDir.resolve("Conference-Paper.md"); assertTrue(Files.exists(expectedFile)); - String content = Files.readString(expectedFile); - - // 'venue' should be populated from 'booktitle' since 'journal' is missing - assertTrue(content.contains("venue: 'Conference Proceedings'")); + List expected = List.of( + "---", + "title: \"Conference Paper\"", + "collection: publications", + "category: InProceedings", + "permalink: /publication/Conference-Paper", + "excerpt: ''", + "date: 2023-01-01", + "venue: 'Unknown'", + "slidesurl: 'https://[insert username].github.io/files/[insert filename].pdf'", + "paperurl: 'https://[insert username].github.io/files/[insert filename].pdf'", + "bibtexurl: 'https://[insert username].github.io/files/[insert filename].bib'", + "citation: '. (2023). \""Conference Paper." .'", + "---", + ""); + + assertEquals(expected, Files.readAllLines(expectedFile)); } } From ad339bef3b6816c745719479b4f1e27c76f47f94 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alo=C3=AFs=20VINCENT?= Date: Tue, 2 Dec 2025 09:32:48 +0100 Subject: [PATCH 21/36] Removed false import statement in tests. --- .../exporter/AcademicPagesExporterTest.java | 221 +++++++++--------- 1 file changed, 110 insertions(+), 111 deletions(-) diff --git a/jablib/src/test/java/org/jabref/logic/exporter/AcademicPagesExporterTest.java b/jablib/src/test/java/org/jabref/logic/exporter/AcademicPagesExporterTest.java index bc7880be7ac..63ed166aeaf 100644 --- a/jablib/src/test/java/org/jabref/logic/exporter/AcademicPagesExporterTest.java +++ b/jablib/src/test/java/org/jabref/logic/exporter/AcademicPagesExporterTest.java @@ -19,7 +19,6 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.jgitunit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.mock; class AcademicPagesExporterTest { @@ -30,21 +29,21 @@ class AcademicPagesExporterTest { @BeforeEach void setUp() { exporter = new AcademicPagesExporter( - mock(LayoutFormatterPreferences.class, Answers.RETURNS_DEEP_STUBS), - new SelfContainedSaveOrder(SaveOrder.OrderType.SPECIFIED, List.of())); + mock(LayoutFormatterPreferences.class, Answers.RETURNS_DEEP_STUBS), + new SelfContainedSaveOrder(SaveOrder.OrderType.SPECIFIED, List.of())); databaseContext = new BibDatabaseContext(); } @Test void exportArticleWithFullDateAndRequiredFieldsGeneratesCorrectFileNameAndContent(@TempDir Path tempDir) throws Exception { BibEntry entry = new BibEntry(StandardEntryType.Article) - .withCitationKey("testKey") - .withField(StandardField.TITLE, "Test Title") - .withField(StandardField.AUTHOR, "Test Author") - .withField(StandardField.YEAR, "2023") - .withField(StandardField.MONTH, "05") - .withField(StandardField.DAY, "12") - .withField(StandardField.JOURNAL, "Test Journal"); + .withCitationKey("testKey") + .withField(StandardField.TITLE, "Test Title") + .withField(StandardField.AUTHOR, "Test Author") + .withField(StandardField.YEAR, "2023") + .withField(StandardField.MONTH, "05") + .withField(StandardField.DAY, "12") + .withField(StandardField.JOURNAL, "Test Journal"); exporter.export(databaseContext, tempDir, List.of(entry)); @@ -53,20 +52,20 @@ void exportArticleWithFullDateAndRequiredFieldsGeneratesCorrectFileNameAndConten assertTrue(Files.exists(expectedFile)); List expected = List.of( - "---", - "title: \"Test Title\"", - "collection: publications", - "category: Article", - "permalink: /publication/Test-Title", - "excerpt: ''", - "date: 2023-05-12", - "venue: 'Test Journal'", - "slidesurl: 'https://[insert username].github.io/files/[insert filename].pdf'", - "paperurl: 'https://[insert username].github.io/files/[insert filename].pdf'", - "bibtexurl: 'https://[insert username].github.io/files/[insert filename].bib'", - "citation: 'Test Author. (2023). \""Test Title." Test Journal.'", - "---", - ""); + "---", + "title: \"Test Title\"", + "collection: publications", + "category: Article", + "permalink: /publication/Test-Title", + "excerpt: ''", + "date: 2023-05-12", + "venue: 'Test Journal'", + "slidesurl: 'https://[insert username].github.io/files/[insert filename].pdf'", + "paperurl: 'https://[insert username].github.io/files/[insert filename].pdf'", + "bibtexurl: 'https://[insert username].github.io/files/[insert filename].bib'", + "citation: 'Test Author. (2023). \""Test Title." Test Journal.'", + "---", + ""); assertEquals(expected, Files.readAllLines(expectedFile)); } @@ -74,9 +73,9 @@ void exportArticleWithFullDateAndRequiredFieldsGeneratesCorrectFileNameAndConten @Test void exportArticleWithMissingMonthAndDayDefaultsToJanuaryFirst(@TempDir Path tempDir) throws Exception { BibEntry entry = new BibEntry(StandardEntryType.Article) - .withCitationKey("testKey") - .withField(StandardField.TITLE, "No Date") - .withField(StandardField.YEAR, "2023"); + .withCitationKey("testKey") + .withField(StandardField.TITLE, "No Date") + .withField(StandardField.YEAR, "2023"); exporter.export(databaseContext, tempDir, List.of(entry)); @@ -85,20 +84,20 @@ void exportArticleWithMissingMonthAndDayDefaultsToJanuaryFirst(@TempDir Path tem assertTrue(Files.exists(expectedFile)); List expected = List.of( - "---", - "title: \"No Date\"", - "collection: publications", - "category: Article", - "permalink: /publication/No-Date", - "excerpt: ''", - "date: 2023-01-01", - "venue: 'Unknown'", - "slidesurl: 'https://[insert username].github.io/files/[insert filename].pdf'", - "paperurl: 'https://[insert username].github.io/files/[insert filename].pdf'", - "bibtexurl: 'https://[insert username].github.io/files/[insert filename].bib'", - "citation: '. (2023). \""No Date." .'", - "---", - ""); + "---", + "title: \"No Date\"", + "collection: publications", + "category: Article", + "permalink: /publication/No-Date", + "excerpt: ''", + "date: 2023-01-01", + "venue: 'Unknown'", + "slidesurl: 'https://[insert username].github.io/files/[insert filename].pdf'", + "paperurl: 'https://[insert username].github.io/files/[insert filename].pdf'", + "bibtexurl: 'https://[insert username].github.io/files/[insert filename].bib'", + "citation: '. (2023). \""No Date." .'", + "---", + ""); assertEquals(expected, Files.readAllLines(expectedFile)); } @@ -106,10 +105,10 @@ void exportArticleWithMissingMonthAndDayDefaultsToJanuaryFirst(@TempDir Path tem @Test void exportArticleWithAbstractAppendsAbstractAfterYamlFrontMatter(@TempDir Path tempDir) throws Exception { BibEntry entry = new BibEntry(StandardEntryType.Article) - .withCitationKey("testKey") - .withField(StandardField.TITLE, "Abstract Paper") - .withField(StandardField.YEAR, "2023") - .withField(StandardField.ABSTRACT, "This is a test abstract."); + .withCitationKey("testKey") + .withField(StandardField.TITLE, "Abstract Paper") + .withField(StandardField.YEAR, "2023") + .withField(StandardField.ABSTRACT, "This is a test abstract."); exporter.export(databaseContext, tempDir, List.of(entry)); @@ -117,20 +116,20 @@ void exportArticleWithAbstractAppendsAbstractAfterYamlFrontMatter(@TempDir Path assertTrue(Files.exists(expectedFile)); List expected = List.of( - "---", - "title: \"Abstract Paper\"", - "collection: publications", - "category: Article", - "permalink: /publication/Abstract-Paper", - "excerpt: ''", - "date: 2023-01-01", - "venue: 'Unknown'", - "slidesurl: 'https://[insert username].github.io/files/[insert filename].pdf'", - "paperurl: 'https://[insert username].github.io/files/[insert filename].pdf'", - "bibtexurl: 'https://[insert username].github.io/files/[insert filename].bib'", - "citation: '. (2023). \""Abstract Paper." .'", - "---", - "This is a test abstract."); + "---", + "title: \"Abstract Paper\"", + "collection: publications", + "category: Article", + "permalink: /publication/Abstract-Paper", + "excerpt: ''", + "date: 2023-01-01", + "venue: 'Unknown'", + "slidesurl: 'https://[insert username].github.io/files/[insert filename].pdf'", + "paperurl: 'https://[insert username].github.io/files/[insert filename].pdf'", + "bibtexurl: 'https://[insert username].github.io/files/[insert filename].bib'", + "citation: '. (2023). \""Abstract Paper." .'", + "---", + "This is a test abstract."); assertEquals(expected, Files.readAllLines(expectedFile)); } @@ -138,14 +137,14 @@ void exportArticleWithAbstractAppendsAbstractAfterYamlFrontMatter(@TempDir Path @Test void exportMultipleEntriesGeneratesMultipleIndividualMarkdownFiles(@TempDir Path tempDir) throws Exception { BibEntry entry1 = new BibEntry(StandardEntryType.Article) - .withCitationKey("key1") - .withField(StandardField.TITLE, "Paper One") - .withField(StandardField.YEAR, "2023"); + .withCitationKey("key1") + .withField(StandardField.TITLE, "Paper One") + .withField(StandardField.YEAR, "2023"); BibEntry entry2 = new BibEntry(StandardEntryType.Book) - .withCitationKey("key2") - .withField(StandardField.TITLE, "Book Two") - .withField(StandardField.YEAR, "2022"); + .withCitationKey("key2") + .withField(StandardField.TITLE, "Book Two") + .withField(StandardField.YEAR, "2022"); exporter.export(databaseContext, tempDir, List.of(entry1, entry2)); @@ -156,47 +155,47 @@ void exportMultipleEntriesGeneratesMultipleIndividualMarkdownFiles(@TempDir Path assertTrue(Files.exists(file2)); List expected1 = List.of( - "---", - "title: \"Paper One\"", - "collection: publications", - "category: Article", - "permalink: /publication/Paper-One", - "excerpt: ''", - "date: 2023-01-01", - "venue: 'Unknown'", - "slidesurl: 'https://[insert username].github.io/files/[insert filename].pdf'", - "paperurl: 'https://[insert username].github.io/files/[insert filename].pdf'", - "bibtexurl: 'https://[insert username].github.io/files/[insert filename].bib'", - "citation: '. (2023). \""Paper One." .'", - "---", - ""); + "---", + "title: \"Paper One\"", + "collection: publications", + "category: Article", + "permalink: /publication/Paper-One", + "excerpt: ''", + "date: 2023-01-01", + "venue: 'Unknown'", + "slidesurl: 'https://[insert username].github.io/files/[insert filename].pdf'", + "paperurl: 'https://[insert username].github.io/files/[insert filename].pdf'", + "bibtexurl: 'https://[insert username].github.io/files/[insert filename].bib'", + "citation: '. (2023). \""Paper One." .'", + "---", + ""); assertEquals(expected1, Files.readAllLines(file1)); List expected2 = List.of( - "---", - "title: \"Book Two\"", - "collection: publications", - "category: Book", - "permalink: /publication/Book-Two", - "excerpt: ''", - "date: 2022-01-01", - "venue: 'Unknown'", - "slidesurl: 'https://[insert username].github.io/files/[insert filename].pdf'", - "paperurl: 'https://[insert username].github.io/files/[insert filename].pdf'", - "bibtexurl: 'https://[insert username].github.io/files/[insert filename].bib'", - "citation: '. (2022). \""Book Two." .'", - "---", - ""); + "---", + "title: \"Book Two\"", + "collection: publications", + "category: Book", + "permalink: /publication/Book-Two", + "excerpt: ''", + "date: 2022-01-01", + "venue: 'Unknown'", + "slidesurl: 'https://[insert username].github.io/files/[insert filename].pdf'", + "paperurl: 'https://[insert username].github.io/files/[insert filename].pdf'", + "bibtexurl: 'https://[insert username].github.io/files/[insert filename].bib'", + "citation: '. (2022). \""Book Two." .'", + "---", + ""); assertEquals(expected2, Files.readAllLines(file2)); } @Test void exportInProceedingsWithBooktitleUsesBooktitleAsVenueAlias(@TempDir Path tempDir) throws Exception { BibEntry entry = new BibEntry(StandardEntryType.InProceedings) - .withCitationKey("testKey") - .withField(StandardField.TITLE, "Conference Paper") - .withField(StandardField.YEAR, "2023") - .withField(StandardField.BOOKTITLE, "Conference Proceedings"); + .withCitationKey("testKey") + .withField(StandardField.TITLE, "Conference Paper") + .withField(StandardField.YEAR, "2023") + .withField(StandardField.BOOKTITLE, "Conference Proceedings"); exporter.export(databaseContext, tempDir, List.of(entry)); @@ -204,20 +203,20 @@ void exportInProceedingsWithBooktitleUsesBooktitleAsVenueAlias(@TempDir Path tem assertTrue(Files.exists(expectedFile)); List expected = List.of( - "---", - "title: \"Conference Paper\"", - "collection: publications", - "category: InProceedings", - "permalink: /publication/Conference-Paper", - "excerpt: ''", - "date: 2023-01-01", - "venue: 'Unknown'", - "slidesurl: 'https://[insert username].github.io/files/[insert filename].pdf'", - "paperurl: 'https://[insert username].github.io/files/[insert filename].pdf'", - "bibtexurl: 'https://[insert username].github.io/files/[insert filename].bib'", - "citation: '. (2023). \""Conference Paper." .'", - "---", - ""); + "---", + "title: \"Conference Paper\"", + "collection: publications", + "category: InProceedings", + "permalink: /publication/Conference-Paper", + "excerpt: ''", + "date: 2023-01-01", + "venue: 'Unknown'", + "slidesurl: 'https://[insert username].github.io/files/[insert filename].pdf'", + "paperurl: 'https://[insert username].github.io/files/[insert filename].pdf'", + "bibtexurl: 'https://[insert username].github.io/files/[insert filename].bib'", + "citation: '. (2023). \""Conference Paper." .'", + "---", + ""); assertEquals(expected, Files.readAllLines(expectedFile)); } From aaa58555e82046f0c69a41166944f817c7e83efe Mon Sep 17 00:00:00 2001 From: Lucie Desnoyers Date: Tue, 2 Dec 2025 09:57:41 +0100 Subject: [PATCH 22/36] deleted useless import in AcademicPagesExporter.java --- .../java/org/jabref/logic/exporter/AcademicPagesExporter.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/jablib/src/main/java/org/jabref/logic/exporter/AcademicPagesExporter.java b/jablib/src/main/java/org/jabref/logic/exporter/AcademicPagesExporter.java index ac707a347e2..98d7727f9a6 100644 --- a/jablib/src/main/java/org/jabref/logic/exporter/AcademicPagesExporter.java +++ b/jablib/src/main/java/org/jabref/logic/exporter/AcademicPagesExporter.java @@ -19,7 +19,6 @@ import org.jabref.model.entry.BibEntry; import org.jabref.model.metadata.SelfContainedSaveOrder; -import org.jetbrains.annotations.NotNull; import org.jspecify.annotations.NonNull; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -110,7 +109,7 @@ public void export(@NonNull final BibDatabaseContext databaseContext, } } - private static @NotNull Path getPath(BibEntry entry, Path exportDirectory) { + private static @NonNull Path getPath(BibEntry entry, Path exportDirectory) { Replace replace_formatter = new Replace(); replace_formatter.setArgument(" ,-"); RemoveLatexCommandsFormatter commands_formatter = new RemoveLatexCommandsFormatter(); From 7b55f273e57a1cdf1d5175d1cdc8120df4ae4c42 Mon Sep 17 00:00:00 2001 From: sadok Date: Tue, 2 Dec 2025 10:20:01 +0100 Subject: [PATCH 23/36] correction of the error given by the localizationconsistancy test --- jablib/src/main/resources/l10n/JabRef_en.properties | 1 - 1 file changed, 1 deletion(-) diff --git a/jablib/src/main/resources/l10n/JabRef_en.properties b/jablib/src/main/resources/l10n/JabRef_en.properties index 9fb9a7274ba..9b1b266fd5d 100644 --- a/jablib/src/main/resources/l10n/JabRef_en.properties +++ b/jablib/src/main/resources/l10n/JabRef_en.properties @@ -472,7 +472,6 @@ The\ marked\ area\ does\ not\ contain\ any\ legible\ text!=The marked area does HTML\ table=HTML table HTML\ table\ (with\ Abstract\ &\ BibTeX)=HTML table (with Abstract & BibTeX) Markdown\ titles=Markdown titles -Markdown\ academicpages=Academic Pages Markdowns Icon=Icon From 7ccbc6fa6d3912023ae32bf8e199720a7d02e756 Mon Sep 17 00:00:00 2001 From: Lucie Desnoyers Date: Fri, 5 Dec 2025 09:06:27 +0100 Subject: [PATCH 24/36] Updated CHANGELOG.md --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 64a10b70918..0d4b87766a0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ Note that this project **does not** adhere to [Semantic Versioning](https://semv ### Added +- We added a custom exporter for academicpages and added the layout format for academic pages. [#12727](...) - We added a drop-down menu to those custom fields in the main table for which content selector values exists. [#14087](https://github.com/JabRef/jabref/issues/14087) - We added a "Jump to Field" dialog (`Ctrl+J`) to quickly search for and navigate to any field across all tabs. [#12276](https://github.com/JabRef/jabref/issues/12276). - We added "IEEE" as another option for parsing plain text citations. [#14233](github.com/JabRef/jabref/pull/14233) From 6f25e5c85854e0712e71efcd3ce8727c1f5fe9e6 Mon Sep 17 00:00:00 2001 From: Lucie Desnoyers Date: Fri, 5 Dec 2025 09:21:29 +0100 Subject: [PATCH 25/36] added the link to issue 12727 --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0d4b87766a0..c97bc6a96aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,7 +11,7 @@ Note that this project **does not** adhere to [Semantic Versioning](https://semv ### Added -- We added a custom exporter for academicpages and added the layout format for academic pages. [#12727](...) +- We added a custom exporter for academicpages and added the layout format for academic pages. [#12727](https://github.com/JabRef/jabref/issues/12727) - We added a drop-down menu to those custom fields in the main table for which content selector values exists. [#14087](https://github.com/JabRef/jabref/issues/14087) - We added a "Jump to Field" dialog (`Ctrl+J`) to quickly search for and navigate to any field across all tabs. [#12276](https://github.com/JabRef/jabref/issues/12276). - We added "IEEE" as another option for parsing plain text citations. [#14233](github.com/JabRef/jabref/pull/14233) From 3c24b327e434f33e63338b72af67c33b06f803f8 Mon Sep 17 00:00:00 2001 From: GreLucie Date: Sat, 6 Dec 2025 13:37:32 +0100 Subject: [PATCH 26/36] Update jablib/src/main/java/org/jabref/logic/exporter/AcademicPagesExporter.java Co-authored-by: Oliver Kopp --- .../java/org/jabref/logic/exporter/AcademicPagesExporter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jablib/src/main/java/org/jabref/logic/exporter/AcademicPagesExporter.java b/jablib/src/main/java/org/jabref/logic/exporter/AcademicPagesExporter.java index 98d7727f9a6..4db78661dfe 100644 --- a/jablib/src/main/java/org/jabref/logic/exporter/AcademicPagesExporter.java +++ b/jablib/src/main/java/org/jabref/logic/exporter/AcademicPagesExporter.java @@ -105,7 +105,7 @@ public void export(@NonNull final BibDatabaseContext databaseContext, academicPagesTemplate.export(databaseContext, path, individual_entry, fileDirForDataBase, abbreviationRepository); } } catch (IOException e) { - throw new SaveException("could not export"); + throw new SaveException("could not export", e); } } From b38bed2b88916fecbc6b69dc0f9af66eee8e34bf Mon Sep 17 00:00:00 2001 From: Lucie Desnoyers Date: Sat, 6 Dec 2025 14:00:47 +0100 Subject: [PATCH 27/36] Adressing some of the comments regarding the PR --- .../logic/exporter/AcademicPagesExporter.java | 38 +++++++++---------- .../layout/format/NumberMonthFormatter.java | 5 +-- 2 files changed, 18 insertions(+), 25 deletions(-) diff --git a/jablib/src/main/java/org/jabref/logic/exporter/AcademicPagesExporter.java b/jablib/src/main/java/org/jabref/logic/exporter/AcademicPagesExporter.java index 4db78661dfe..4bbba0c2bd6 100644 --- a/jablib/src/main/java/org/jabref/logic/exporter/AcademicPagesExporter.java +++ b/jablib/src/main/java/org/jabref/logic/exporter/AcademicPagesExporter.java @@ -36,7 +36,7 @@ public class AcademicPagesExporter extends Exporter { private static final Logger LOGGER = LoggerFactory.getLogger(AcademicPagesExporter.class); - private final String lfFileName; + private final String layoutFileFileName; private final String directory; private final LayoutFormatterPreferences layoutPreferences; private final SelfContainedSaveOrder saveOrder; @@ -45,22 +45,22 @@ public class AcademicPagesExporter extends Exporter { private TemplateExporter academicPagesTemplate; /** - * Initialize another export format based on templates stored in dir with layoutFile lfFilename. + * Initialize another export format based on templates stored in directory. * */ public AcademicPagesExporter(LayoutFormatterPreferences layoutPreferences, SelfContainedSaveOrder saveOrder) { super("academicpages", "academic pages markdowns", StandardFileType.MARKDOWN); - this.lfFileName = "academicpages"; + this.layoutFileFileName = "academicpages"; this.directory = "academicpages"; this.layoutPreferences = layoutPreferences; this.saveOrder = saveOrder; String consoleName = "academicpages"; - this.academicPagesTemplate = new TemplateExporter("academicpages", consoleName, lfFileName, directory, StandardFileType.MARKDOWN, layoutPreferences, saveOrder); + this.academicPagesTemplate = new TemplateExporter("academicpages", consoleName, layoutFileFileName, directory, StandardFileType.MARKDOWN, layoutPreferences, saveOrder); } @Override public void export(@NonNull final BibDatabaseContext databaseContext, - final Path exportDirectory, + @NonNull final Path exportDirectory, @NonNull List entries) throws SaveException { export(databaseContext, exportDirectory, entries, List.of(), JournalAbbreviationLoader.loadBuiltInRepository()); } @@ -76,7 +76,7 @@ public void export(@NonNull final BibDatabaseContext databaseContext, */ @Override public void export(@NonNull final BibDatabaseContext databaseContext, - final Path file, + @NonNull final Path file, @NonNull List entries, List fileDirForDataBase, JournalAbbreviationRepository abbreviationRepository) throws SaveException { @@ -93,16 +93,12 @@ public void export(@NonNull final BibDatabaseContext databaseContext, Files.createDirectories(exportDirectory); for (BibEntry entry : entries) { - if (entry.getType() == null) { - LOGGER.warn("Skipping entry with no type: {}", entry); - continue; - } // formatting the title of each entry to match the file names format demanded by academic pages (applying the same formatters applied to the title in the academicpages.layout) Path path = getPath(entry, exportDirectory); - List individual_entry = new ArrayList<>(); - individual_entry.add(entry); - academicPagesTemplate.export(databaseContext, path, individual_entry, fileDirForDataBase, abbreviationRepository); + List individualEntry = new ArrayList<>(); + individualEntry.add(entry); + academicPagesTemplate.export(databaseContext, path, individualEntry, fileDirForDataBase, abbreviationRepository); } } catch (IOException e) { throw new SaveException("could not export", e); @@ -110,14 +106,14 @@ public void export(@NonNull final BibDatabaseContext databaseContext, } private static @NonNull Path getPath(BibEntry entry, Path exportDirectory) { - Replace replace_formatter = new Replace(); - replace_formatter.setArgument(" ,-"); - RemoveLatexCommandsFormatter commands_formatter = new RemoveLatexCommandsFormatter(); - HTMLChars html_formatter = new HTMLChars(); + Replace replaceFormatter = new Replace(); + replaceFormatter.setArgument(" ,-"); + RemoveLatexCommandsFormatter commandsFormatter = new RemoveLatexCommandsFormatter(); + HTMLChars htmlFormatter = new HTMLChars(); String title = entry.getTitle().get(); - String formatted_title = commands_formatter.format(html_formatter.format(replace_formatter.format(title))); - SafeFileName safe_formatter = new SafeFileName(); // added custom formatter to remove all characters that are not allowed in filenames - String safe_title = safe_formatter.format(formatted_title); - return exportDirectory.resolve(safe_title + ".md"); + String formattedTitle = commandsFormatter.format(htmlFormatter.format(replaceFormatter.format(title))); + SafeFileName safeFormatter = new SafeFileName(); + String safeTitle = safeFormatter.format(formattedTitle); + return exportDirectory.resolve(safeTitle + ".md"); } } diff --git a/jablib/src/main/java/org/jabref/logic/layout/format/NumberMonthFormatter.java b/jablib/src/main/java/org/jabref/logic/layout/format/NumberMonthFormatter.java index 06d3a0e86eb..da2aae5254e 100644 --- a/jablib/src/main/java/org/jabref/logic/layout/format/NumberMonthFormatter.java +++ b/jablib/src/main/java/org/jabref/logic/layout/format/NumberMonthFormatter.java @@ -1,7 +1,5 @@ package org.jabref.logic.layout.format; -import java.util.Optional; - import org.jabref.logic.layout.LayoutFormatter; import org.jabref.model.entry.Month; @@ -12,7 +10,6 @@ public class NumberMonthFormatter implements LayoutFormatter { @Override public String format(String fieldText) { - Optional month = Month.parse(fieldText); - return month.map(Month::getTwoDigitNumber).orElse("01"); + return Month.parse(fieldText).map(Month::getTwoDigitNumber).orElse("01"); } } From c2a06e0ef64b6c4310a86b871976dcf522354aff Mon Sep 17 00:00:00 2001 From: Lucie Desnoyers Date: Sat, 6 Dec 2025 14:19:44 +0100 Subject: [PATCH 28/36] Comment added for replaceFormatter.setArgument(' ,-') --- .../java/org/jabref/logic/exporter/AcademicPagesExporter.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jablib/src/main/java/org/jabref/logic/exporter/AcademicPagesExporter.java b/jablib/src/main/java/org/jabref/logic/exporter/AcademicPagesExporter.java index 4bbba0c2bd6..11150fe4823 100644 --- a/jablib/src/main/java/org/jabref/logic/exporter/AcademicPagesExporter.java +++ b/jablib/src/main/java/org/jabref/logic/exporter/AcademicPagesExporter.java @@ -107,7 +107,7 @@ public void export(@NonNull final BibDatabaseContext databaseContext, private static @NonNull Path getPath(BibEntry entry, Path exportDirectory) { Replace replaceFormatter = new Replace(); - replaceFormatter.setArgument(" ,-"); + replaceFormatter.setArgument(" ,-"); // The replaceFormatter expects a "-" instead of " " hence the strange argument. RemoveLatexCommandsFormatter commandsFormatter = new RemoveLatexCommandsFormatter(); HTMLChars htmlFormatter = new HTMLChars(); String title = entry.getTitle().get(); From 280a1fbed8a969c5f2822deaafb7b275b04aa9cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alo=C3=AFs=20VINCENT?= Date: Sat, 6 Dec 2025 15:42:03 +0100 Subject: [PATCH 29/36] tests: added 4 test cases and specified the SaveException --- .../logic/exporter/AcademicPagesExporter.java | 13 +- jablib/src/main/resources/csl-styles | 2 +- .../exporter/AcademicPagesExporterTest.java | 501 +++++++++++------- 3 files changed, 313 insertions(+), 203 deletions(-) diff --git a/jablib/src/main/java/org/jabref/logic/exporter/AcademicPagesExporter.java b/jablib/src/main/java/org/jabref/logic/exporter/AcademicPagesExporter.java index 11150fe4823..3c4d4896074 100644 --- a/jablib/src/main/java/org/jabref/logic/exporter/AcademicPagesExporter.java +++ b/jablib/src/main/java/org/jabref/logic/exporter/AcademicPagesExporter.java @@ -27,6 +27,7 @@ * A custom exporter to write multiple bib entries as AcademicPages Markdown format. */ public class AcademicPagesExporter extends Exporter { + private static final String BLANK_LINE_PATTERN = "\\r\\n|\\n"; private static final String LAYOUT_PREFIX = "/resource/layout/"; private static final String LAYOUT_EXTENSION = ".layout"; @@ -61,8 +62,9 @@ public AcademicPagesExporter(LayoutFormatterPreferences layoutPreferences, SelfC @Override public void export(@NonNull final BibDatabaseContext databaseContext, @NonNull final Path exportDirectory, - @NonNull List entries) throws SaveException { - export(databaseContext, exportDirectory, entries, List.of(), JournalAbbreviationLoader.loadBuiltInRepository()); + @NonNull List entries) + throws SaveException { + export(databaseContext, exportDirectory, entries, List.of(exportDirectory), JournalAbbreviationLoader.loadBuiltInRepository()); } /** @@ -79,7 +81,8 @@ public void export(@NonNull final BibDatabaseContext databaseContext, @NonNull final Path file, @NonNull List entries, List fileDirForDataBase, - JournalAbbreviationRepository abbreviationRepository) throws SaveException { + JournalAbbreviationRepository abbreviationRepository) + throws SaveException { if (entries.isEmpty()) { // Only export if entries exist return; } @@ -105,12 +108,12 @@ public void export(@NonNull final BibDatabaseContext databaseContext, } } - private static @NonNull Path getPath(BibEntry entry, Path exportDirectory) { + private static @NonNull Path getPath(BibEntry entry, Path exportDirectory) throws SaveException { Replace replaceFormatter = new Replace(); replaceFormatter.setArgument(" ,-"); // The replaceFormatter expects a "-" instead of " " hence the strange argument. RemoveLatexCommandsFormatter commandsFormatter = new RemoveLatexCommandsFormatter(); HTMLChars htmlFormatter = new HTMLChars(); - String title = entry.getTitle().get(); + String title = entry.getTitle().orElseThrow(() -> new SaveException("Entry does not contain a title")); String formattedTitle = commandsFormatter.format(htmlFormatter.format(replaceFormatter.format(title))); SafeFileName safeFormatter = new SafeFileName(); String safeTitle = safeFormatter.format(formattedTitle); diff --git a/jablib/src/main/resources/csl-styles b/jablib/src/main/resources/csl-styles index 2e282387c2e..5f4f6aea729 160000 --- a/jablib/src/main/resources/csl-styles +++ b/jablib/src/main/resources/csl-styles @@ -1 +1 @@ -Subproject commit 2e282387c2e67848011bff2b9fcd60639e5d4eee +Subproject commit 5f4f6aea729cd0debcf42ff34fa8451bd7691d55 diff --git a/jablib/src/test/java/org/jabref/logic/exporter/AcademicPagesExporterTest.java b/jablib/src/test/java/org/jabref/logic/exporter/AcademicPagesExporterTest.java index 63ed166aeaf..139a74dd01b 100644 --- a/jablib/src/test/java/org/jabref/logic/exporter/AcademicPagesExporterTest.java +++ b/jablib/src/test/java/org/jabref/logic/exporter/AcademicPagesExporterTest.java @@ -18,206 +18,313 @@ import org.mockito.Answers; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.mock; class AcademicPagesExporterTest { - private AcademicPagesExporter exporter; - private BibDatabaseContext databaseContext; - - @BeforeEach - void setUp() { - exporter = new AcademicPagesExporter( - mock(LayoutFormatterPreferences.class, Answers.RETURNS_DEEP_STUBS), - new SelfContainedSaveOrder(SaveOrder.OrderType.SPECIFIED, List.of())); - databaseContext = new BibDatabaseContext(); - } - - @Test - void exportArticleWithFullDateAndRequiredFieldsGeneratesCorrectFileNameAndContent(@TempDir Path tempDir) throws Exception { - BibEntry entry = new BibEntry(StandardEntryType.Article) - .withCitationKey("testKey") - .withField(StandardField.TITLE, "Test Title") - .withField(StandardField.AUTHOR, "Test Author") - .withField(StandardField.YEAR, "2023") - .withField(StandardField.MONTH, "05") - .withField(StandardField.DAY, "12") - .withField(StandardField.JOURNAL, "Test Journal"); - - exporter.export(databaseContext, tempDir, List.of(entry)); - - // Verify file name follows pattern: title.md (SafeFileName) - Path expectedFile = tempDir.resolve("Test-Title.md"); - assertTrue(Files.exists(expectedFile)); - - List expected = List.of( - "---", - "title: \"Test Title\"", - "collection: publications", - "category: Article", - "permalink: /publication/Test-Title", - "excerpt: ''", - "date: 2023-05-12", - "venue: 'Test Journal'", - "slidesurl: 'https://[insert username].github.io/files/[insert filename].pdf'", - "paperurl: 'https://[insert username].github.io/files/[insert filename].pdf'", - "bibtexurl: 'https://[insert username].github.io/files/[insert filename].bib'", - "citation: 'Test Author. (2023). \""Test Title." Test Journal.'", - "---", - ""); - - assertEquals(expected, Files.readAllLines(expectedFile)); - } - - @Test - void exportArticleWithMissingMonthAndDayDefaultsToJanuaryFirst(@TempDir Path tempDir) throws Exception { - BibEntry entry = new BibEntry(StandardEntryType.Article) - .withCitationKey("testKey") - .withField(StandardField.TITLE, "No Date") - .withField(StandardField.YEAR, "2023"); - - exporter.export(databaseContext, tempDir, List.of(entry)); - - // Expect default date 2023-01-01 - Path expectedFile = tempDir.resolve("No-Date.md"); - assertTrue(Files.exists(expectedFile)); - - List expected = List.of( - "---", - "title: \"No Date\"", - "collection: publications", - "category: Article", - "permalink: /publication/No-Date", - "excerpt: ''", - "date: 2023-01-01", - "venue: 'Unknown'", - "slidesurl: 'https://[insert username].github.io/files/[insert filename].pdf'", - "paperurl: 'https://[insert username].github.io/files/[insert filename].pdf'", - "bibtexurl: 'https://[insert username].github.io/files/[insert filename].bib'", - "citation: '. (2023). \""No Date." .'", - "---", - ""); - - assertEquals(expected, Files.readAllLines(expectedFile)); - } - - @Test - void exportArticleWithAbstractAppendsAbstractAfterYamlFrontMatter(@TempDir Path tempDir) throws Exception { - BibEntry entry = new BibEntry(StandardEntryType.Article) - .withCitationKey("testKey") - .withField(StandardField.TITLE, "Abstract Paper") - .withField(StandardField.YEAR, "2023") - .withField(StandardField.ABSTRACT, "This is a test abstract."); - - exporter.export(databaseContext, tempDir, List.of(entry)); - - Path expectedFile = tempDir.resolve("Abstract-Paper.md"); - assertTrue(Files.exists(expectedFile)); - - List expected = List.of( - "---", - "title: \"Abstract Paper\"", - "collection: publications", - "category: Article", - "permalink: /publication/Abstract-Paper", - "excerpt: ''", - "date: 2023-01-01", - "venue: 'Unknown'", - "slidesurl: 'https://[insert username].github.io/files/[insert filename].pdf'", - "paperurl: 'https://[insert username].github.io/files/[insert filename].pdf'", - "bibtexurl: 'https://[insert username].github.io/files/[insert filename].bib'", - "citation: '. (2023). \""Abstract Paper." .'", - "---", - "This is a test abstract."); - - assertEquals(expected, Files.readAllLines(expectedFile)); - } - - @Test - void exportMultipleEntriesGeneratesMultipleIndividualMarkdownFiles(@TempDir Path tempDir) throws Exception { - BibEntry entry1 = new BibEntry(StandardEntryType.Article) - .withCitationKey("key1") - .withField(StandardField.TITLE, "Paper One") - .withField(StandardField.YEAR, "2023"); - - BibEntry entry2 = new BibEntry(StandardEntryType.Book) - .withCitationKey("key2") - .withField(StandardField.TITLE, "Book Two") - .withField(StandardField.YEAR, "2022"); - - exporter.export(databaseContext, tempDir, List.of(entry1, entry2)); - - // Verify both files exist - Path file1 = tempDir.resolve("Paper-One.md"); - Path file2 = tempDir.resolve("Book-Two.md"); - assertTrue(Files.exists(file1)); - assertTrue(Files.exists(file2)); - - List expected1 = List.of( - "---", - "title: \"Paper One\"", - "collection: publications", - "category: Article", - "permalink: /publication/Paper-One", - "excerpt: ''", - "date: 2023-01-01", - "venue: 'Unknown'", - "slidesurl: 'https://[insert username].github.io/files/[insert filename].pdf'", - "paperurl: 'https://[insert username].github.io/files/[insert filename].pdf'", - "bibtexurl: 'https://[insert username].github.io/files/[insert filename].bib'", - "citation: '. (2023). \""Paper One." .'", - "---", - ""); - assertEquals(expected1, Files.readAllLines(file1)); - - List expected2 = List.of( - "---", - "title: \"Book Two\"", - "collection: publications", - "category: Book", - "permalink: /publication/Book-Two", - "excerpt: ''", - "date: 2022-01-01", - "venue: 'Unknown'", - "slidesurl: 'https://[insert username].github.io/files/[insert filename].pdf'", - "paperurl: 'https://[insert username].github.io/files/[insert filename].pdf'", - "bibtexurl: 'https://[insert username].github.io/files/[insert filename].bib'", - "citation: '. (2022). \""Book Two." .'", - "---", - ""); - assertEquals(expected2, Files.readAllLines(file2)); - } - - @Test - void exportInProceedingsWithBooktitleUsesBooktitleAsVenueAlias(@TempDir Path tempDir) throws Exception { - BibEntry entry = new BibEntry(StandardEntryType.InProceedings) - .withCitationKey("testKey") - .withField(StandardField.TITLE, "Conference Paper") - .withField(StandardField.YEAR, "2023") - .withField(StandardField.BOOKTITLE, "Conference Proceedings"); - - exporter.export(databaseContext, tempDir, List.of(entry)); - - Path expectedFile = tempDir.resolve("Conference-Paper.md"); - assertTrue(Files.exists(expectedFile)); - - List expected = List.of( - "---", - "title: \"Conference Paper\"", - "collection: publications", - "category: InProceedings", - "permalink: /publication/Conference-Paper", - "excerpt: ''", - "date: 2023-01-01", - "venue: 'Unknown'", - "slidesurl: 'https://[insert username].github.io/files/[insert filename].pdf'", - "paperurl: 'https://[insert username].github.io/files/[insert filename].pdf'", - "bibtexurl: 'https://[insert username].github.io/files/[insert filename].bib'", - "citation: '. (2023). \""Conference Paper." .'", - "---", - ""); - - assertEquals(expected, Files.readAllLines(expectedFile)); - } + private AcademicPagesExporter exporter; + private BibDatabaseContext databaseContext; + + @BeforeEach + void setUp() { + exporter = new AcademicPagesExporter( + mock(LayoutFormatterPreferences.class, Answers.RETURNS_DEEP_STUBS), + new SelfContainedSaveOrder(SaveOrder.OrderType.SPECIFIED, List.of())); + databaseContext = new BibDatabaseContext(); + } + + @Test + void exportArticleWithFullDateAndRequiredFieldsGeneratesCorrectFileNameAndContent(@TempDir Path tempDir) throws Exception { + BibEntry entry = new BibEntry(StandardEntryType.Article) + .withCitationKey("testKey") + .withField(StandardField.TITLE, "Test Title") + .withField(StandardField.AUTHOR, "Test Author") + .withField(StandardField.YEAR, "2023") + .withField(StandardField.MONTH, "05") + .withField(StandardField.DAY, "12") + .withField(StandardField.JOURNAL, "Test Journal"); + + exporter.export(databaseContext, tempDir, List.of(entry)); + + // Verify file name follows pattern: title.md (SafeFileName) + Path expectedFile = tempDir.resolve("Test-Title.md"); + assertTrue(Files.exists(expectedFile)); + + List expected = List.of( + "---", + "title: \"Test Title\"", + "collection: publications", + "category: Article", + "permalink: /publication/Test-Title", + "excerpt: ''", + "date: 2023-05-12", + "venue: 'Test Journal'", + "slidesurl: 'https://[insert username].github.io/files/[insert filename].pdf'", + "paperurl: 'https://[insert username].github.io/files/[insert filename].pdf'", + "bibtexurl: 'https://[insert username].github.io/files/[insert filename].bib'", + "citation: 'Test Author. (2023). \""Test Title." Test Journal.'", + "---", + ""); + + assertEquals(expected, Files.readAllLines(expectedFile)); + } + + @Test + void exportArticleWithMissingMonthAndDayDefaultsToJanuaryFirst(@TempDir Path tempDir) throws Exception { + BibEntry entry = new BibEntry(StandardEntryType.Article) + .withCitationKey("testKey") + .withField(StandardField.TITLE, "No Date") + .withField(StandardField.YEAR, "2023"); + + exporter.export(databaseContext, tempDir, List.of(entry)); + + // Expect default date 2023-01-01 + Path expectedFile = tempDir.resolve("No-Date.md"); + assertTrue(Files.exists(expectedFile)); + + List expected = List.of( + "---", + "title: \"No Date\"", + "collection: publications", + "category: Article", + "permalink: /publication/No-Date", + "excerpt: ''", + "date: 2023-01-01", + "venue: 'Unknown'", + "slidesurl: 'https://[insert username].github.io/files/[insert filename].pdf'", + "paperurl: 'https://[insert username].github.io/files/[insert filename].pdf'", + "bibtexurl: 'https://[insert username].github.io/files/[insert filename].bib'", + "citation: '. (2023). \""No Date." .'", + "---", + ""); + + assertEquals(expected, Files.readAllLines(expectedFile)); + } + + @Test + void exportArticleWithAbstractAppendsAbstractAfterYamlFrontMatter(@TempDir Path tempDir) throws Exception { + BibEntry entry = new BibEntry(StandardEntryType.Article) + .withCitationKey("testKey") + .withField(StandardField.TITLE, "Abstract Paper") + .withField(StandardField.YEAR, "2023") + .withField(StandardField.ABSTRACT, "This is a test abstract."); + + exporter.export(databaseContext, tempDir, List.of(entry)); + + Path expectedFile = tempDir.resolve("Abstract-Paper.md"); + assertTrue(Files.exists(expectedFile)); + + List expected = List.of( + "---", + "title: \"Abstract Paper\"", + "collection: publications", + "category: Article", + "permalink: /publication/Abstract-Paper", + "excerpt: ''", + "date: 2023-01-01", + "venue: 'Unknown'", + "slidesurl: 'https://[insert username].github.io/files/[insert filename].pdf'", + "paperurl: 'https://[insert username].github.io/files/[insert filename].pdf'", + "bibtexurl: 'https://[insert username].github.io/files/[insert filename].bib'", + "citation: '. (2023). \""Abstract Paper." .'", + "---", + "This is a test abstract."); + + assertEquals(expected, Files.readAllLines(expectedFile)); + } + + @Test + void exportMultipleEntriesGeneratesMultipleIndividualMarkdownFiles(@TempDir Path tempDir) throws Exception { + BibEntry entry1 = new BibEntry(StandardEntryType.Article) + .withCitationKey("key1") + .withField(StandardField.TITLE, "Paper One") + .withField(StandardField.YEAR, "2023"); + + BibEntry entry2 = new BibEntry(StandardEntryType.Book) + .withCitationKey("key2") + .withField(StandardField.TITLE, "Book Two") + .withField(StandardField.YEAR, "2022"); + + exporter.export(databaseContext, tempDir, List.of(entry1, entry2)); + + // Verify both files exist + Path file1 = tempDir.resolve("Paper-One.md"); + Path file2 = tempDir.resolve("Book-Two.md"); + assertTrue(Files.exists(file1)); + assertTrue(Files.exists(file2)); + + List expected1 = List.of( + "---", + "title: \"Paper One\"", + "collection: publications", + "category: Article", + "permalink: /publication/Paper-One", + "excerpt: ''", + "date: 2023-01-01", + "venue: 'Unknown'", + "slidesurl: 'https://[insert username].github.io/files/[insert filename].pdf'", + "paperurl: 'https://[insert username].github.io/files/[insert filename].pdf'", + "bibtexurl: 'https://[insert username].github.io/files/[insert filename].bib'", + "citation: '. (2023). \""Paper One." .'", + "---", + ""); + assertEquals(expected1, Files.readAllLines(file1)); + + List expected2 = List.of( + "---", + "title: \"Book Two\"", + "collection: publications", + "category: Book", + "permalink: /publication/Book-Two", + "excerpt: ''", + "date: 2022-01-01", + "venue: 'Unknown'", + "slidesurl: 'https://[insert username].github.io/files/[insert filename].pdf'", + "paperurl: 'https://[insert username].github.io/files/[insert filename].pdf'", + "bibtexurl: 'https://[insert username].github.io/files/[insert filename].bib'", + "citation: '. (2022). \""Book Two." .'", + "---", + ""); + assertEquals(expected2, Files.readAllLines(file2)); + } + + @Test + void exportInProceedingsWithBooktitleUsesBooktitleAsVenueAlias(@TempDir Path tempDir) throws Exception { + BibEntry entry = new BibEntry(StandardEntryType.InProceedings) + .withCitationKey("testKey") + .withField(StandardField.TITLE, "Conference Paper") + .withField(StandardField.YEAR, "2023") + .withField(StandardField.BOOKTITLE, "Conference Proceedings"); + + exporter.export(databaseContext, tempDir, List.of(entry)); + + Path expectedFile = tempDir.resolve("Conference-Paper.md"); + assertTrue(Files.exists(expectedFile)); + + List expected = List.of( + "---", + "title: \"Conference Paper\"", + "collection: publications", + "category: InProceedings", + "permalink: /publication/Conference-Paper", + "excerpt: ''", + "date: 2023-01-01", + "venue: 'Unknown'", + "slidesurl: 'https://[insert username].github.io/files/[insert filename].pdf'", + "paperurl: 'https://[insert username].github.io/files/[insert filename].pdf'", + "bibtexurl: 'https://[insert username].github.io/files/[insert filename].bib'", + "citation: '. (2023). \""Conference Paper." .'", + "---", + ""); + + assertEquals(expected, Files.readAllLines(expectedFile)); + } + + @Test + void exportArticleWithSpecialCharactersInTitleGeneratesSafeFileName(@TempDir Path tempDir) throws Exception { + BibEntry entry = new BibEntry(StandardEntryType.Article) + .withCitationKey("testKey") + .withField(StandardField.TITLE, "test title \\/:*?\"<>|") + .withField(StandardField.YEAR, "2024"); + + exporter.export(databaseContext, tempDir, List.of(entry)); + + // Resulting file name should be safe: test-title-.md + Path expectedFile = tempDir.resolve("test-title-.md"); + assertTrue(Files.exists(expectedFile)); + + List expected = List.of( + "---", + "title: \"test title /:*?\"<>|\"", + "collection: publications", + "category: Article", + "permalink: /publication/test-title-", + "excerpt: ''", + "date: 2024-01-01", + "venue: 'Unknown'", + "slidesurl: 'https://[insert username].github.io/files/[insert filename].pdf'", + "paperurl: 'https://[insert username].github.io/files/[insert filename].pdf'", + "bibtexurl: 'https://[insert username].github.io/files/[insert filename].bib'", + "citation: '. (2024). \""test title /:*?\"<>|." .'", + "---", + ""); + + assertEquals(expected, Files.readAllLines(expectedFile)); + } + + @Test + void exportArticleWithFileFieldGeneratesSlidesAndPaperUrls(@TempDir Path tempDir) throws Exception { + BibEntry entry = new BibEntry(StandardEntryType.Article) + .withCitationKey("testKey") + .withField(StandardField.TITLE, "test title") + .withField(StandardField.YEAR, "2024") + .withField(StandardField.FILE, ":arxiv.pdf:PDF"); + + exporter.export(databaseContext, tempDir, List.of(entry)); + + Path expectedFile = tempDir.resolve("test-title.md"); + assertTrue(Files.exists(expectedFile)); + + List expected = List.of( + "---", + "title: \"test title\"", + "collection: publications", + "category: Article", + "permalink: /publication/test-title", + "excerpt: ''", + "date: 2024-01-01", + "venue: 'Unknown'", + "slidesurl: 'arxiv.pdf'", + "paperurl: 'arxiv.pdf'", + "bibtexurl: 'https://[insert username].github.io/files/[insert filename].bib'", + "citation: '. (2024). \""test title." .'", + "---", + ""); + + assertEquals(expected, Files.readAllLines(expectedFile)); + } + + @Test + void exportArticleWithNoTitleThrowsSaveException(@TempDir Path tempDir) { + BibEntry entry = new BibEntry(StandardEntryType.Article) + .withCitationKey("testKey"); + + assertThrows(SaveException.class, () -> exporter.export(databaseContext, tempDir, List.of(entry))); + } + + @Test + void exportArticleWithSpacesInTitleReplacesSpacesWithDashesInPermalink(@TempDir Path tempDir) throws Exception { + BibEntry entry = new BibEntry(StandardEntryType.Article) + .withCitationKey("testKey") + .withField(StandardField.TITLE, "test title") + .withField(StandardField.YEAR, "2024") + .withField(StandardField.MONTH, "01") + .withField(StandardField.DAY, "01"); + + exporter.export(databaseContext, tempDir, List.of(entry)); + + // Resulting file name should replace spaces with dashes + Path expectedFile = tempDir.resolve("test---title.md"); + assertTrue(Files.exists(expectedFile)); + + List expected = List.of( + "---", + "title: \"test title\"", + "collection: publications", + "category: Article", + "permalink: /publication/test---title", + "excerpt: ''", + "date: 2024-01-01", + "venue: 'Unknown'", + "slidesurl: 'https://[insert username].github.io/files/[insert filename].pdf'", + "paperurl: 'https://[insert username].github.io/files/[insert filename].pdf'", + "bibtexurl: 'https://[insert username].github.io/files/[insert filename].bib'", + "citation: '. (2024). \""test title." .'", + "---", + ""); + + assertEquals(expected, Files.readAllLines(expectedFile)); + } } From 6a4c5b0c95761173f9a25c4e43e04a08a41240e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alo=C3=AFs=20VINCENT?= Date: Sat, 6 Dec 2025 16:36:16 +0100 Subject: [PATCH 30/36] Fixed submodules? --- jablib/src/main/resources/csl-styles | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/jablib/src/main/resources/csl-styles b/jablib/src/main/resources/csl-styles index 5f4f6aea729..2e282387c2e 160000 --- a/jablib/src/main/resources/csl-styles +++ b/jablib/src/main/resources/csl-styles @@ -1 +1 @@ -Subproject commit 5f4f6aea729cd0debcf42ff34fa8451bd7691d55 +Subproject commit 2e282387c2e67848011bff2b9fcd60639e5d4eee From 100fe95fd2e80d7e86a23d3ade55de7117501700 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9lina=20Wang?= Date: Sat, 6 Dec 2025 16:49:02 +0100 Subject: [PATCH 31/36] add all formatters as class variable --- .../logic/exporter/AcademicPagesExporter.java | 28 +++++++------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/jablib/src/main/java/org/jabref/logic/exporter/AcademicPagesExporter.java b/jablib/src/main/java/org/jabref/logic/exporter/AcademicPagesExporter.java index 3c4d4896074..3db4d5fc91b 100644 --- a/jablib/src/main/java/org/jabref/logic/exporter/AcademicPagesExporter.java +++ b/jablib/src/main/java/org/jabref/logic/exporter/AcademicPagesExporter.java @@ -20,29 +20,22 @@ import org.jabref.model.metadata.SelfContainedSaveOrder; import org.jspecify.annotations.NonNull; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** * A custom exporter to write multiple bib entries as AcademicPages Markdown format. */ public class AcademicPagesExporter extends Exporter { - private static final String BLANK_LINE_PATTERN = "\\r\\n|\\n"; - private static final String LAYOUT_PREFIX = "/resource/layout/"; - private static final String LAYOUT_EXTENSION = ".layout"; - private static final String FORMATTERS_EXTENSION = ".formatters"; - private static final String BEGIN_INFIX = ".begin"; - private static final String END_INFIX = ".end"; - - private static final Logger LOGGER = LoggerFactory.getLogger(AcademicPagesExporter.class); - private final String layoutFileFileName; private final String directory; private final LayoutFormatterPreferences layoutPreferences; private final SelfContainedSaveOrder saveOrder; - private boolean customExport; - private List entries; + + private final Replace replaceFormatter = new Replace(); + private final RemoveLatexCommandsFormatter commandsFormatter = new RemoveLatexCommandsFormatter(); + private final HTMLChars htmlFormatter = new HTMLChars(); + private final SafeFileName safeFormatter = new SafeFileName(); + private TemplateExporter academicPagesTemplate; /** @@ -108,15 +101,14 @@ public void export(@NonNull final BibDatabaseContext databaseContext, } } - private static @NonNull Path getPath(BibEntry entry, Path exportDirectory) throws SaveException { - Replace replaceFormatter = new Replace(); + private @NonNull Path getPath(BibEntry entry, Path exportDirectory) throws SaveException { + replaceFormatter.setArgument(" ,-"); // The replaceFormatter expects a "-" instead of " " hence the strange argument. - RemoveLatexCommandsFormatter commandsFormatter = new RemoveLatexCommandsFormatter(); - HTMLChars htmlFormatter = new HTMLChars(); + String title = entry.getTitle().orElseThrow(() -> new SaveException("Entry does not contain a title")); String formattedTitle = commandsFormatter.format(htmlFormatter.format(replaceFormatter.format(title))); - SafeFileName safeFormatter = new SafeFileName(); String safeTitle = safeFormatter.format(formattedTitle); + return exportDirectory.resolve(safeTitle + ".md"); } } From 07088a8e087d59c908ee49ce2ccd9a69c72f7508 Mon Sep 17 00:00:00 2001 From: Lucie Desnoyers Date: Sat, 6 Dec 2025 18:01:29 +0100 Subject: [PATCH 32/36] changed a comment --- .../logic/exporter/AcademicPagesExporter.java | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/jablib/src/main/java/org/jabref/logic/exporter/AcademicPagesExporter.java b/jablib/src/main/java/org/jabref/logic/exporter/AcademicPagesExporter.java index 11150fe4823..836c76a4491 100644 --- a/jablib/src/main/java/org/jabref/logic/exporter/AcademicPagesExporter.java +++ b/jablib/src/main/java/org/jabref/logic/exporter/AcademicPagesExporter.java @@ -20,28 +20,16 @@ import org.jabref.model.metadata.SelfContainedSaveOrder; import org.jspecify.annotations.NonNull; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** * A custom exporter to write multiple bib entries as AcademicPages Markdown format. */ public class AcademicPagesExporter extends Exporter { - private static final String BLANK_LINE_PATTERN = "\\r\\n|\\n"; - private static final String LAYOUT_PREFIX = "/resource/layout/"; - private static final String LAYOUT_EXTENSION = ".layout"; - private static final String FORMATTERS_EXTENSION = ".formatters"; - private static final String BEGIN_INFIX = ".begin"; - private static final String END_INFIX = ".end"; - - private static final Logger LOGGER = LoggerFactory.getLogger(AcademicPagesExporter.class); private final String layoutFileFileName; private final String directory; private final LayoutFormatterPreferences layoutPreferences; private final SelfContainedSaveOrder saveOrder; - private boolean customExport; - private List entries; private TemplateExporter academicPagesTemplate; /** @@ -107,7 +95,7 @@ public void export(@NonNull final BibDatabaseContext databaseContext, private static @NonNull Path getPath(BibEntry entry, Path exportDirectory) { Replace replaceFormatter = new Replace(); - replaceFormatter.setArgument(" ,-"); // The replaceFormatter expects a "-" instead of " " hence the strange argument. + replaceFormatter.setArgument(" ,-"); // expects an expression that has the character to remove and the replacement character separated by a comma. RemoveLatexCommandsFormatter commandsFormatter = new RemoveLatexCommandsFormatter(); HTMLChars htmlFormatter = new HTMLChars(); String title = entry.getTitle().get(); From 1efe4a2ccdb98410b6f64ad477b16e9d643eee7c Mon Sep 17 00:00:00 2001 From: Lucie Desnoyers Date: Sat, 6 Dec 2025 18:39:11 +0100 Subject: [PATCH 33/36] Revert change on AcademicPagesExporter --- .../logic/exporter/AcademicPagesExporter.java | 30 ++++--------------- 1 file changed, 6 insertions(+), 24 deletions(-) diff --git a/jablib/src/main/java/org/jabref/logic/exporter/AcademicPagesExporter.java b/jablib/src/main/java/org/jabref/logic/exporter/AcademicPagesExporter.java index 08257ec2afd..80d9e895f35 100644 --- a/jablib/src/main/java/org/jabref/logic/exporter/AcademicPagesExporter.java +++ b/jablib/src/main/java/org/jabref/logic/exporter/AcademicPagesExporter.java @@ -20,25 +20,17 @@ import org.jabref.model.metadata.SelfContainedSaveOrder; import org.jspecify.annotations.NonNull; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * A custom exporter to write multiple bib entries as AcademicPages Markdown format. */ public class AcademicPagesExporter extends Exporter { - private final String layoutFileFileName; private final String directory; private final LayoutFormatterPreferences layoutPreferences; private final SelfContainedSaveOrder saveOrder; -<<<<<<< HEAD -======= - - private final Replace replaceFormatter = new Replace(); - private final RemoveLatexCommandsFormatter commandsFormatter = new RemoveLatexCommandsFormatter(); - private final HTMLChars htmlFormatter = new HTMLChars(); - private final SafeFileName safeFormatter = new SafeFileName(); - ->>>>>>> 100fe95fd2e80d7e86a23d3ade55de7117501700 private TemplateExporter academicPagesTemplate; /** @@ -58,9 +50,8 @@ public AcademicPagesExporter(LayoutFormatterPreferences layoutPreferences, SelfC @Override public void export(@NonNull final BibDatabaseContext databaseContext, @NonNull final Path exportDirectory, - @NonNull List entries) - throws SaveException { - export(databaseContext, exportDirectory, entries, List.of(exportDirectory), JournalAbbreviationLoader.loadBuiltInRepository()); + @NonNull List entries) throws SaveException { + export(databaseContext, exportDirectory, entries, List.of(), JournalAbbreviationLoader.loadBuiltInRepository()); } /** @@ -77,8 +68,7 @@ public void export(@NonNull final BibDatabaseContext databaseContext, @NonNull final Path file, @NonNull List entries, List fileDirForDataBase, - JournalAbbreviationRepository abbreviationRepository) - throws SaveException { + JournalAbbreviationRepository abbreviationRepository) throws SaveException { if (entries.isEmpty()) { // Only export if entries exist return; } @@ -104,23 +94,15 @@ public void export(@NonNull final BibDatabaseContext databaseContext, } } -<<<<<<< HEAD private static @NonNull Path getPath(BibEntry entry, Path exportDirectory) { Replace replaceFormatter = new Replace(); replaceFormatter.setArgument(" ,-"); // expects an expression that has the character to remove and the replacement character separated by a comma. RemoveLatexCommandsFormatter commandsFormatter = new RemoveLatexCommandsFormatter(); HTMLChars htmlFormatter = new HTMLChars(); String title = entry.getTitle().get(); -======= - private @NonNull Path getPath(BibEntry entry, Path exportDirectory) throws SaveException { - - replaceFormatter.setArgument(" ,-"); // The replaceFormatter expects a "-" instead of " " hence the strange argument. - - String title = entry.getTitle().orElseThrow(() -> new SaveException("Entry does not contain a title")); ->>>>>>> 100fe95fd2e80d7e86a23d3ade55de7117501700 String formattedTitle = commandsFormatter.format(htmlFormatter.format(replaceFormatter.format(title))); + SafeFileName safeFormatter = new SafeFileName(); String safeTitle = safeFormatter.format(formattedTitle); - return exportDirectory.resolve(safeTitle + ".md"); } } From 488620dd59d87cf14ded7f29054e887a7e14273f Mon Sep 17 00:00:00 2001 From: Lucie Desnoyers Date: Sat, 6 Dec 2025 18:52:58 +0100 Subject: [PATCH 34/36] Fixed some indentation in AcademicPagesExporterTest --- .../exporter/AcademicPagesExporterTest.java | 545 +++++++++--------- 1 file changed, 272 insertions(+), 273 deletions(-) diff --git a/jablib/src/test/java/org/jabref/logic/exporter/AcademicPagesExporterTest.java b/jablib/src/test/java/org/jabref/logic/exporter/AcademicPagesExporterTest.java index 9c108ef05d9..968ecd1b283 100644 --- a/jablib/src/test/java/org/jabref/logic/exporter/AcademicPagesExporterTest.java +++ b/jablib/src/test/java/org/jabref/logic/exporter/AcademicPagesExporterTest.java @@ -23,277 +23,276 @@ import static org.mockito.Mockito.mock; class AcademicPagesExporterTest { - - private AcademicPagesExporter exporter; - private BibDatabaseContext databaseContext; - - @BeforeEach - void setUp() { - exporter = new AcademicPagesExporter(mock(LayoutFormatterPreferences.class, Answers.RETURNS_DEEP_STUBS), new SelfContainedSaveOrder(SaveOrder.OrderType.SPECIFIED, List.of())); - databaseContext = new BibDatabaseContext(); - } - - @Test - void exportArticleWithFullDateAndRequiredFieldsGeneratesCorrectFileNameAndContent(@TempDir Path tempDir) throws Exception { - BibEntry entry = new BibEntry(StandardEntryType.Article).withCitationKey("testKey") - .withField(StandardField.TITLE, "Test Title") - .withField(StandardField.AUTHOR, "Test Author") - .withField(StandardField.YEAR, "2023") - .withField(StandardField.MONTH, "05") - .withField(StandardField.DAY, "12") - .withField(StandardField.JOURNAL, "Test Journal"); - - exporter.export(databaseContext, tempDir, List.of(entry)); - - // Verify file name follows pattern: title.md (SafeFileName) - Path expectedFile = tempDir.resolve("Test-Title.md"); - assertTrue(Files.exists(expectedFile)); - - List expected = List.of("---", - "title: \"Test Title\"", - "collection: publications", - "category: Article", - "permalink: /publication/Test-Title", - "excerpt: ''", - "date: 2023-05-12", - "venue: 'Test Journal'", - "slidesurl: 'https://[insert username].github.io/files/[insert filename].pdf'", - "paperurl: 'https://[insert username].github.io/files/[insert filename].pdf'", - "bibtexurl: 'https://[insert username].github.io/files/[insert filename].bib'", - "citation: 'Test Author. (2023). \""Test Title." Test Journal.'", - "---", - ""); - assertEquals(expected, Files.readAllLines(expectedFile)); - } - - @Test - void exportArticleWithMissingMonthAndDayDefaultsToJanuaryFirst(@TempDir Path tempDir) throws Exception { - BibEntry entry = new BibEntry(StandardEntryType.Article).withCitationKey("testKey") - .withField(StandardField.TITLE, "No Date") - .withField(StandardField.YEAR, "2023"); - exporter.export(databaseContext, tempDir, List.of(entry)); - - // Expect default date 2023-01-01 - Path expectedFile = tempDir.resolve("No-Date.md"); - assertTrue(Files.exists(expectedFile)); - - List expected = List.of("---", - "title: \"No Date\"", - "collection: publications", - "category: Article", - "permalink: /publication/No-Date", - "excerpt: ''", - "date: 2023-01-01", - "venue: 'Unknown'", - "slidesurl: 'https://[insert username].github.io/files/[insert filename].pdf'", - "paperurl: 'https://[insert username].github.io/files/[insert filename].pdf'", - "bibtexurl: 'https://[insert username].github.io/files/[insert filename].bib'", - "citation: '. (2023). \""No Date." .'", - "---", - ""); - assertEquals(expected, Files.readAllLines(expectedFile)); - } - - @Test - void exportArticleWithAbstractAppendsAbstractAfterYamlFrontMatter(@TempDir Path tempDir) throws Exception { - BibEntry entry = new BibEntry(StandardEntryType.Article).withCitationKey("testKey") - .withField(StandardField.TITLE, "Abstract Paper") - .withField(StandardField.YEAR, "2023") - .withField(StandardField.ABSTRACT, "This is a test abstract."); - exporter.export(databaseContext, tempDir, List.of(entry)); - - Path expectedFile = tempDir.resolve("Abstract-Paper.md"); - assertTrue(Files.exists(expectedFile)); - - List expected = List.of("---", - "title: \"Abstract Paper\"", - "collection: publications", - "category: Article", - "permalink: /publication/Abstract-Paper", - "excerpt: ''", - "date: 2023-01-01", - "venue: 'Unknown'", - "slidesurl: 'https://[insert username].github.io/files/[insert filename].pdf'", - "paperurl: 'https://[insert username].github.io/files/[insert filename].pdf'", - "bibtexurl: 'https://[insert username].github.io/files/[insert filename].bib'", - "citation: '. (2023). \""Abstract Paper." .'", - "---", - "This is a test abstract."); - - assertEquals(expected, Files.readAllLines(expectedFile)); - } - - @Test - void exportMultipleEntriesGeneratesMultipleIndividualMarkdownFiles(@TempDir Path tempDir) throws Exception { - BibEntry entry1 = new BibEntry(StandardEntryType.Article).withCitationKey("key1") - .withField(StandardField.TITLE, "Paper One") - .withField(StandardField.YEAR, "2023"); - - BibEntry entry2 = new BibEntry(StandardEntryType.Book).withCitationKey("key2") - .withField(StandardField.TITLE, "Book Two") - .withField(StandardField.YEAR, "2022"); - - exporter.export(databaseContext, tempDir, List.of(entry1, entry2)); - - // Verify both files exist - Path file1 = tempDir.resolve("Paper-One.md"); - Path file2 = tempDir.resolve("Book-Two.md"); - assertTrue(Files.exists(file1)); - assertTrue(Files.exists(file2)); - - List expected1 = List.of("---", - "title: \"Paper One\"", - "collection: publications", - "category: Article", - "permalink: /publication/Paper-One", - "excerpt: ''", - "date: 2023-01-01", - "venue: 'Unknown'", - "slidesurl: 'https://[insert username].github.io/files/[insert filename].pdf'", - "paperurl: 'https://[insert username].github.io/files/[insert filename].pdf'", - "bibtexurl: 'https://[insert username].github.io/files/[insert filename].bib'", - "citation: '. (2023). \""Paper One." .'", - "---", - ""); - assertEquals(expected1, Files.readAllLines(file1)); - - List expected2 = List.of("---", - "title: \"Book Two\"", - "collection: publications", - "category: Book", - "permalink: /publication/Book-Two", - "excerpt: ''", - "date: 2022-01-01", - "venue: 'Unknown'", - "slidesurl: 'https://[insert username].github.io/files/[insert filename].pdf'", - "paperurl: 'https://[insert username].github.io/files/[insert filename].pdf'", - "bibtexurl: 'https://[insert username].github.io/files/[insert filename].bib'", - "citation: '. (2022). \""Book Two." .'", - "---", - ""); - assertEquals(expected2, Files.readAllLines(file2)); - } - - @Test - void exportInProceedingsWithBooktitleUsesBooktitleAsVenueAlias(@TempDir Path tempDir) throws Exception { - BibEntry entry = new BibEntry(StandardEntryType.InProceedings).withCitationKey("testKey") - .withField(StandardField.TITLE, "Conference Paper") - .withField(StandardField.YEAR, "2023") - .withField(StandardField.BOOKTITLE, "Conference Proceedings"); - - exporter.export(databaseContext, tempDir, List.of(entry)); - - Path expectedFile = tempDir.resolve("Conference-Paper.md"); - assertTrue(Files.exists(expectedFile)); - - List expected = List.of("---", - "title: \"Conference Paper\"", - "collection: publications", - "category: InProceedings", - "permalink: /publication/Conference-Paper", - "excerpt: ''", - "date: 2023-01-01", - "venue: 'Unknown'", - "slidesurl: 'https://[insert username].github.io/files/[insert filename].pdf'", - "paperurl: 'https://[insert username].github.io/files/[insert filename].pdf'", - "bibtexurl: 'https://[insert username].github.io/files/[insert filename].bib'", - "citation: '. (2023). \""Conference Paper." .'", - "---", - ""); - assertEquals(expected, Files.readAllLines(expectedFile)); - } - - @Test - void exportArticleWithSpecialCharactersInTitleGeneratesSafeFileName(@TempDir Path tempDir) throws Exception { - BibEntry entry = new BibEntry(StandardEntryType.Article).withCitationKey("testKey") - .withField(StandardField.TITLE, "test title \\/:*?\"<>|") - .withField(StandardField.YEAR, "2024"); - - exporter.export(databaseContext, tempDir, List.of(entry)); - - // Resulting file name should be safe: test-title-.md - Path expectedFile = tempDir.resolve("test-title-.md"); - assertTrue(Files.exists(expectedFile)); - - List expected = List.of("---", - "title: \"test title /:*?\"<>|\"", - "collection: publications", - "category: Article", - "permalink: /publication/test-title-", - "excerpt: ''", - "date: 2024-01-01", - "venue: 'Unknown'", - "slidesurl: 'https://[insert username].github.io/files/[insert filename].pdf'", - "paperurl: 'https://[insert username].github.io/files/[insert filename].pdf'", - "bibtexurl: 'https://[insert username].github.io/files/[insert filename].bib'", - "citation: '. (2024). \""test title /:*?\"<>|." .'", - "---", - ""); - assertEquals(expected, Files.readAllLines(expectedFile)); - } - - @Test - void exportArticleWithFileFieldGeneratesSlidesAndPaperUrls(@TempDir Path tempDir) throws Exception { - BibEntry entry = new BibEntry(StandardEntryType.Article).withCitationKey("testKey") - .withField(StandardField.TITLE, "test title") - .withField(StandardField.YEAR, "2024") - .withField(StandardField.FILE, ":arxiv.pdf:PDF"); - exporter.export(databaseContext, tempDir, List.of(entry)); - - Path expectedFile = tempDir.resolve("test-title.md"); - assertTrue(Files.exists(expectedFile)); - - List expected = List.of("---", - "title: \"test title\"", - "collection: publications", - "category: Article", - "permalink: /publication/test-title", - "excerpt: ''", - "date: 2024-01-01", - "venue: 'Unknown'", - "slidesurl: 'arxiv.pdf'", - "paperurl: 'arxiv.pdf'", - "bibtexurl: 'https://[insert username].github.io/files/[insert filename].bib'", - "citation: '. (2024). \""test title." .'", - "---", - ""); - assertEquals(expected, Files.readAllLines(expectedFile)); - } - - @Test - void exportArticleWithNoTitleThrowsSaveException(@TempDir Path tempDir) { - BibEntry entry = new BibEntry(StandardEntryType.Article).withCitationKey("testKey"); - assertThrows(SaveException.class, () -> exporter.export(databaseContext, tempDir, List.of(entry))); - } - - @Test - void exportArticleWithSpacesInTitleReplacesSpacesWithDashesInPermalink(@TempDir Path tempDir) throws Exception { - BibEntry entry = new BibEntry(StandardEntryType.Article).withCitationKey("testKey") - .withField(StandardField.TITLE, "test title") - .withField(StandardField.YEAR, "2024") - .withField(StandardField.MONTH, "01") - .withField(StandardField.DAY, "01"); - exporter.export(databaseContext, tempDir, List.of(entry)); - - // Resulting file name should replace spaces with dashes - Path expectedFile = tempDir.resolve("test---title.md"); - assertTrue(Files.exists(expectedFile)); - - List expected = List.of("---", - "title: \"test title\"", - "collection: publications", - "category: Article", - "permalink: /publication/test---title", - "excerpt: ''", - "date: 2024-01-01", - "venue: 'Unknown'", - "slidesurl: 'https://[insert username].github.io/files/[insert filename].pdf'", - "paperurl: 'https://[insert username].github.io/files/[insert filename].pdf'", - "bibtexurl: 'https://[insert username].github.io/files/[insert filename].bib'", - "citation: '. (2024). \""test title." .'", - "---", - ""); - - assertEquals(expected, Files.readAllLines(expectedFile)); - } + private AcademicPagesExporter exporter; + private BibDatabaseContext databaseContext; + + @BeforeEach + void setUp() { + exporter = new AcademicPagesExporter(mock(LayoutFormatterPreferences.class, Answers.RETURNS_DEEP_STUBS), new SelfContainedSaveOrder(SaveOrder.OrderType.SPECIFIED, List.of())); + databaseContext = new BibDatabaseContext(); + } + + @Test + void exportArticleWithFullDateAndRequiredFieldsGeneratesCorrectFileNameAndContent(@TempDir Path tempDir) throws Exception { + BibEntry entry = new BibEntry(StandardEntryType.Article).withCitationKey("testKey") + .withField(StandardField.TITLE, "Test Title") + .withField(StandardField.AUTHOR, "Test Author") + .withField(StandardField.YEAR, "2023") + .withField(StandardField.MONTH, "05") + .withField(StandardField.DAY, "12") + .withField(StandardField.JOURNAL, "Test Journal"); + + exporter.export(databaseContext, tempDir, List.of(entry)); + + // Verify file name follows pattern: title.md (SafeFileName) + Path expectedFile = tempDir.resolve("Test-Title.md"); + assertTrue(Files.exists(expectedFile)); + + List expected = List.of("---", + "title: \"Test Title\"", + "collection: publications", + "category: Article", + "permalink: /publication/Test-Title", + "excerpt: ''", + "date: 2023-05-12", + "venue: 'Test Journal'", + "slidesurl: 'https://[insert username].github.io/files/[insert filename].pdf'", + "paperurl: 'https://[insert username].github.io/files/[insert filename].pdf'", + "bibtexurl: 'https://[insert username].github.io/files/[insert filename].bib'", + "citation: 'Test Author. (2023). \""Test Title." Test Journal.'", + "---", + ""); + assertEquals(expected, Files.readAllLines(expectedFile)); + } + + @Test + void exportArticleWithMissingMonthAndDayDefaultsToJanuaryFirst(@TempDir Path tempDir) throws Exception { + BibEntry entry = new BibEntry(StandardEntryType.Article).withCitationKey("testKey") + .withField(StandardField.TITLE, "No Date") + .withField(StandardField.YEAR, "2023"); + exporter.export(databaseContext, tempDir, List.of(entry)); + + // Expect default date 2023-01-01 + Path expectedFile = tempDir.resolve("No-Date.md"); + assertTrue(Files.exists(expectedFile)); + + List expected = List.of("---", + "title: \"No Date\"", + "collection: publications", + "category: Article", + "permalink: /publication/No-Date", + "excerpt: ''", + "date: 2023-01-01", + "venue: 'Unknown'", + "slidesurl: 'https://[insert username].github.io/files/[insert filename].pdf'", + "paperurl: 'https://[insert username].github.io/files/[insert filename].pdf'", + "bibtexurl: 'https://[insert username].github.io/files/[insert filename].bib'", + "citation: '. (2023). \""No Date." .'", + "---", + ""); + assertEquals(expected, Files.readAllLines(expectedFile)); + } + + @Test + void exportArticleWithAbstractAppendsAbstractAfterYamlFrontMatter(@TempDir Path tempDir) throws Exception { + BibEntry entry = new BibEntry(StandardEntryType.Article).withCitationKey("testKey") + .withField(StandardField.TITLE, "Abstract Paper") + .withField(StandardField.YEAR, "2023") + .withField(StandardField.ABSTRACT, "This is a test abstract."); + exporter.export(databaseContext, tempDir, List.of(entry)); + + Path expectedFile = tempDir.resolve("Abstract-Paper.md"); + assertTrue(Files.exists(expectedFile)); + + List expected = List.of("---", + "title: \"Abstract Paper\"", + "collection: publications", + "category: Article", + "permalink: /publication/Abstract-Paper", + "excerpt: ''", + "date: 2023-01-01", + "venue: 'Unknown'", + "slidesurl: 'https://[insert username].github.io/files/[insert filename].pdf'", + "paperurl: 'https://[insert username].github.io/files/[insert filename].pdf'", + "bibtexurl: 'https://[insert username].github.io/files/[insert filename].bib'", + "citation: '. (2023). \""Abstract Paper." .'", + "---", + "This is a test abstract."); + + assertEquals(expected, Files.readAllLines(expectedFile)); + } + + @Test + void exportMultipleEntriesGeneratesMultipleIndividualMarkdownFiles(@TempDir Path tempDir) throws Exception { + BibEntry entry1 = new BibEntry(StandardEntryType.Article).withCitationKey("key1") + .withField(StandardField.TITLE, "Paper One") + .withField(StandardField.YEAR, "2023"); + + BibEntry entry2 = new BibEntry(StandardEntryType.Book).withCitationKey("key2") + .withField(StandardField.TITLE, "Book Two") + .withField(StandardField.YEAR, "2022"); + + exporter.export(databaseContext, tempDir, List.of(entry1, entry2)); + + // Verify both files exist + Path file1 = tempDir.resolve("Paper-One.md"); + Path file2 = tempDir.resolve("Book-Two.md"); + assertTrue(Files.exists(file1)); + assertTrue(Files.exists(file2)); + + List expected1 = List.of("---", + "title: \"Paper One\"", + "collection: publications", + "category: Article", + "permalink: /publication/Paper-One", + "excerpt: ''", + "date: 2023-01-01", + "venue: 'Unknown'", + "slidesurl: 'https://[insert username].github.io/files/[insert filename].pdf'", + "paperurl: 'https://[insert username].github.io/files/[insert filename].pdf'", + "bibtexurl: 'https://[insert username].github.io/files/[insert filename].bib'", + "citation: '. (2023). \""Paper One." .'", + "---", + ""); + assertEquals(expected1, Files.readAllLines(file1)); + + List expected2 = List.of("---", + "title: \"Book Two\"", + "collection: publications", + "category: Book", + "permalink: /publication/Book-Two", + "excerpt: ''", + "date: 2022-01-01", + "venue: 'Unknown'", + "slidesurl: 'https://[insert username].github.io/files/[insert filename].pdf'", + "paperurl: 'https://[insert username].github.io/files/[insert filename].pdf'", + "bibtexurl: 'https://[insert username].github.io/files/[insert filename].bib'", + "citation: '. (2022). \""Book Two." .'", + "---", + ""); + assertEquals(expected2, Files.readAllLines(file2)); + } + + @Test + void exportInProceedingsWithBooktitleUsesBooktitleAsVenueAlias(@TempDir Path tempDir) throws Exception { + BibEntry entry = new BibEntry(StandardEntryType.InProceedings).withCitationKey("testKey") + .withField(StandardField.TITLE, "Conference Paper") + .withField(StandardField.YEAR, "2023") + .withField(StandardField.BOOKTITLE, "Conference Proceedings"); + + exporter.export(databaseContext, tempDir, List.of(entry)); + + Path expectedFile = tempDir.resolve("Conference-Paper.md"); + assertTrue(Files.exists(expectedFile)); + + List expected = List.of("---", + "title: \"Conference Paper\"", + "collection: publications", + "category: InProceedings", + "permalink: /publication/Conference-Paper", + "excerpt: ''", + "date: 2023-01-01", + "venue: 'Unknown'", + "slidesurl: 'https://[insert username].github.io/files/[insert filename].pdf'", + "paperurl: 'https://[insert username].github.io/files/[insert filename].pdf'", + "bibtexurl: 'https://[insert username].github.io/files/[insert filename].bib'", + "citation: '. (2023). \""Conference Paper." .'", + "---", + ""); + assertEquals(expected, Files.readAllLines(expectedFile)); + } + + @Test + void exportArticleWithSpecialCharactersInTitleGeneratesSafeFileName(@TempDir Path tempDir) throws Exception { + BibEntry entry = new BibEntry(StandardEntryType.Article).withCitationKey("testKey") + .withField(StandardField.TITLE, "test title \\/:*?\"<>|") + .withField(StandardField.YEAR, "2024"); + + exporter.export(databaseContext, tempDir, List.of(entry)); + + // Resulting file name should be safe: test-title-.md + Path expectedFile = tempDir.resolve("test-title-.md"); + assertTrue(Files.exists(expectedFile)); + + List expected = List.of("---", + "title: \"test title /:*?\"<>|\"", + "collection: publications", + "category: Article", + "permalink: /publication/test-title-", + "excerpt: ''", + "date: 2024-01-01", + "venue: 'Unknown'", + "slidesurl: 'https://[insert username].github.io/files/[insert filename].pdf'", + "paperurl: 'https://[insert username].github.io/files/[insert filename].pdf'", + "bibtexurl: 'https://[insert username].github.io/files/[insert filename].bib'", + "citation: '. (2024). \""test title /:*?\"<>|." .'", + "---", + ""); + assertEquals(expected, Files.readAllLines(expectedFile)); + } + + @Test + void exportArticleWithFileFieldGeneratesSlidesAndPaperUrls(@TempDir Path tempDir) throws Exception { + BibEntry entry = new BibEntry(StandardEntryType.Article).withCitationKey("testKey") + .withField(StandardField.TITLE, "test title") + .withField(StandardField.YEAR, "2024") + .withField(StandardField.FILE, ":arxiv.pdf:PDF"); + exporter.export(databaseContext, tempDir, List.of(entry)); + + Path expectedFile = tempDir.resolve("test-title.md"); + assertTrue(Files.exists(expectedFile)); + + List expected = List.of("---", + "title: \"test title\"", + "collection: publications", + "category: Article", + "permalink: /publication/test-title", + "excerpt: ''", + "date: 2024-01-01", + "venue: 'Unknown'", + "slidesurl: 'arxiv.pdf'", + "paperurl: 'arxiv.pdf'", + "bibtexurl: 'https://[insert username].github.io/files/[insert filename].bib'", + "citation: '. (2024). \""test title." .'", + "---", + ""); + assertEquals(expected, Files.readAllLines(expectedFile)); + } + + @Test + void exportArticleWithNoTitleThrowsSaveException(@TempDir Path tempDir) { + BibEntry entry = new BibEntry(StandardEntryType.Article).withCitationKey("testKey"); + assertThrows(SaveException.class, () -> exporter.export(databaseContext, tempDir, List.of(entry))); + } + + @Test + void exportArticleWithSpacesInTitleReplacesSpacesWithDashesInPermalink(@TempDir Path tempDir) throws Exception { + BibEntry entry = new BibEntry(StandardEntryType.Article).withCitationKey("testKey") + .withField(StandardField.TITLE, "test title") + .withField(StandardField.YEAR, "2024") + .withField(StandardField.MONTH, "01") + .withField(StandardField.DAY, "01"); + exporter.export(databaseContext, tempDir, List.of(entry)); + + // Resulting file name should replace spaces with dashes + Path expectedFile = tempDir.resolve("test---title.md"); + assertTrue(Files.exists(expectedFile)); + + List expected = List.of("---", + "title: \"test title\"", + "collection: publications", + "category: Article", + "permalink: /publication/test---title", + "excerpt: ''", + "date: 2024-01-01", + "venue: 'Unknown'", + "slidesurl: 'https://[insert username].github.io/files/[insert filename].pdf'", + "paperurl: 'https://[insert username].github.io/files/[insert filename].pdf'", + "bibtexurl: 'https://[insert username].github.io/files/[insert filename].bib'", + "citation: '. (2024). \""test title." .'", + "---", + ""); + + assertEquals(expected, Files.readAllLines(expectedFile)); + } } From 5d6e3a276b3217487ba015f56001cf17115a0a8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A9lina=20Wang?= Date: Sat, 6 Dec 2025 19:30:09 +0100 Subject: [PATCH 35/36] add all formatters as class variable --- .../logic/exporter/AcademicPagesExporter.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/jablib/src/main/java/org/jabref/logic/exporter/AcademicPagesExporter.java b/jablib/src/main/java/org/jabref/logic/exporter/AcademicPagesExporter.java index 80d9e895f35..8163143bde5 100644 --- a/jablib/src/main/java/org/jabref/logic/exporter/AcademicPagesExporter.java +++ b/jablib/src/main/java/org/jabref/logic/exporter/AcademicPagesExporter.java @@ -20,8 +20,6 @@ import org.jabref.model.metadata.SelfContainedSaveOrder; import org.jspecify.annotations.NonNull; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; /** * A custom exporter to write multiple bib entries as AcademicPages Markdown format. @@ -31,6 +29,12 @@ public class AcademicPagesExporter extends Exporter { private final String directory; private final LayoutFormatterPreferences layoutPreferences; private final SelfContainedSaveOrder saveOrder; + + private final Replace replaceFormatter = new Replace(); + private final RemoveLatexCommandsFormatter commandsFormatter = new RemoveLatexCommandsFormatter(); + private final HTMLChars htmlFormatter = new HTMLChars(); + private final SafeFileName safeFormatter = new SafeFileName(); + private TemplateExporter academicPagesTemplate; /** @@ -94,14 +98,10 @@ public void export(@NonNull final BibDatabaseContext databaseContext, } } - private static @NonNull Path getPath(BibEntry entry, Path exportDirectory) { - Replace replaceFormatter = new Replace(); + private @NonNull Path getPath(BibEntry entry, Path exportDirectory) { replaceFormatter.setArgument(" ,-"); // expects an expression that has the character to remove and the replacement character separated by a comma. - RemoveLatexCommandsFormatter commandsFormatter = new RemoveLatexCommandsFormatter(); - HTMLChars htmlFormatter = new HTMLChars(); String title = entry.getTitle().get(); String formattedTitle = commandsFormatter.format(htmlFormatter.format(replaceFormatter.format(title))); - SafeFileName safeFormatter = new SafeFileName(); String safeTitle = safeFormatter.format(formattedTitle); return exportDirectory.resolve(safeTitle + ".md"); } From 91a6a05211778749cba2fc56ca3fc33ff534ce48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alo=C3=AFs=20VINCENT?= Date: Sun, 7 Dec 2025 15:17:34 +0100 Subject: [PATCH 36/36] Fixed tests not passing. --- .../org/jabref/logic/exporter/AcademicPagesExporter.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/jablib/src/main/java/org/jabref/logic/exporter/AcademicPagesExporter.java b/jablib/src/main/java/org/jabref/logic/exporter/AcademicPagesExporter.java index 8163143bde5..2b0018fec38 100644 --- a/jablib/src/main/java/org/jabref/logic/exporter/AcademicPagesExporter.java +++ b/jablib/src/main/java/org/jabref/logic/exporter/AcademicPagesExporter.java @@ -55,7 +55,7 @@ public AcademicPagesExporter(LayoutFormatterPreferences layoutPreferences, SelfC public void export(@NonNull final BibDatabaseContext databaseContext, @NonNull final Path exportDirectory, @NonNull List entries) throws SaveException { - export(databaseContext, exportDirectory, entries, List.of(), JournalAbbreviationLoader.loadBuiltInRepository()); + export(databaseContext, exportDirectory, entries, List.of(exportDirectory), JournalAbbreviationLoader.loadBuiltInRepository()); } /** @@ -98,9 +98,9 @@ public void export(@NonNull final BibDatabaseContext databaseContext, } } - private @NonNull Path getPath(BibEntry entry, Path exportDirectory) { + private @NonNull Path getPath(BibEntry entry, Path exportDirectory) throws SaveException { replaceFormatter.setArgument(" ,-"); // expects an expression that has the character to remove and the replacement character separated by a comma. - String title = entry.getTitle().get(); + String title = entry.getTitle().orElseThrow(() -> new SaveException("Entry is missing a title")); String formattedTitle = commandsFormatter.format(htmlFormatter.format(replaceFormatter.format(title))); String safeTitle = safeFormatter.format(formattedTitle); return exportDirectory.resolve(safeTitle + ".md");