diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b4e10494f9..65c782451b6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ Note that this project **does not** adhere to [Semantic Versioning](https://semv - We added a link "Get more themes..." in the preferences to that points to [themes.jabref.org](https://themes.jabref.org) allowing the user to download new themes. [#10243](https://github.com/JabRef/jabref/issues/10243) - We added a fetcher for [LOBID](https://lobid.org/resources/api) resources. [koppor#386](https://github.com/koppor/jabref/issues/386) - When in `biblatex` mode, the [integrity check](https://docs.jabref.org/finding-sorting-and-cleaning-entries/checkintegrity) for journal titles now also checks the field `journal`. +- We added support for exporting to Hayagriva YAML format. [#10382](https://github.com/JabRef/jabref/issues/10382) - We added support for pushing citations to [TeXShop](https://pages.uoregon.edu/koch/texshop/) on macOS [forum#2699](https://discourse.jabref.org/t/push-to-texshop-mac/2699). ### Changed diff --git a/src/main/java/org/jabref/logic/exporter/ExporterFactory.java b/src/main/java/org/jabref/logic/exporter/ExporterFactory.java index 4eaa28e4dea..b38bb57dc95 100644 --- a/src/main/java/org/jabref/logic/exporter/ExporterFactory.java +++ b/src/main/java/org/jabref/logic/exporter/ExporterFactory.java @@ -54,6 +54,7 @@ public static ExporterFactory create(PreferencesService preferencesService, exporters.add(new TemplateExporter("RIS", "ris", "ris", "ris", StandardFileType.RIS, layoutPreferences, saveOrder, BlankLineBehaviour.DELETE_BLANKS)); 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 OpenOfficeDocumentCreator()); exporters.add(new OpenDocumentSpreadsheetCreator()); exporters.add(new MSBibExporter()); diff --git a/src/main/java/org/jabref/logic/layout/LayoutEntry.java b/src/main/java/org/jabref/logic/layout/LayoutEntry.java index cafd87dc8bc..b739393a982 100644 --- a/src/main/java/org/jabref/logic/layout/LayoutEntry.java +++ b/src/main/java/org/jabref/logic/layout/LayoutEntry.java @@ -54,6 +54,7 @@ import org.jabref.logic.layout.format.GetOpenOfficeType; import org.jabref.logic.layout.format.HTMLChars; import org.jabref.logic.layout.format.HTMLParagraphs; +import org.jabref.logic.layout.format.HayagrivaType; import org.jabref.logic.layout.format.IfPlural; import org.jabref.logic.layout.format.Iso690FormatDate; import org.jabref.logic.layout.format.Iso690NamesAuthors; @@ -484,6 +485,7 @@ private LayoutFormatter getLayoutFormatterByName(String name) { case "CSLType" -> new CSLType(); case "ShortMonth" -> new ShortMonthFormatter(); case "ReplaceWithEscapedDoubleQuotes" -> new ReplaceWithEscapedDoubleQuotes(); + case "HayagrivaType" -> new HayagrivaType(); default -> null; }; } diff --git a/src/main/java/org/jabref/logic/layout/format/HayagrivaType.java b/src/main/java/org/jabref/logic/layout/format/HayagrivaType.java new file mode 100644 index 00000000000..cbe30bf06d5 --- /dev/null +++ b/src/main/java/org/jabref/logic/layout/format/HayagrivaType.java @@ -0,0 +1,23 @@ +package org.jabref.logic.layout.format; + +import org.jabref.logic.layout.LayoutFormatter; +import org.jabref.model.entry.types.StandardEntryType; + +public class HayagrivaType implements LayoutFormatter { + + @Override + public String format(String value) { + return switch (StandardEntryType.valueOf(value)) { + case Article, Conference -> "article"; + case Book -> "book"; + case InBook -> "chapter"; + case Report, TechReport -> "report"; + case Thesis, MastersThesis, PhdThesis -> "thesis"; + case WWW, Online -> "web"; + case Proceedings -> "proceedings"; + case Reference -> "reference"; + + default -> "Misc"; + }; + } +} diff --git a/src/main/resources/resource/layout/hayagrivayaml.begin.layout b/src/main/resources/resource/layout/hayagrivayaml.begin.layout new file mode 100644 index 00000000000..ed97d539c09 --- /dev/null +++ b/src/main/resources/resource/layout/hayagrivayaml.begin.layout @@ -0,0 +1 @@ +--- diff --git a/src/main/resources/resource/layout/hayagrivayaml.end.layout b/src/main/resources/resource/layout/hayagrivayaml.end.layout new file mode 100644 index 00000000000..ed97d539c09 --- /dev/null +++ b/src/main/resources/resource/layout/hayagrivayaml.end.layout @@ -0,0 +1 @@ +--- diff --git a/src/main/resources/resource/layout/hayagrivayaml.layout b/src/main/resources/resource/layout/hayagrivayaml.layout new file mode 100644 index 00000000000..cd19524d406 --- /dev/null +++ b/src/main/resources/resource/layout/hayagrivayaml.layout @@ -0,0 +1,21 @@ +\citationkey: +\begin{entrytype} type: \format[HayagrivaType]{\entrytype}\end{entrytype} +\begin{title} title: "\title"\end{title} +\begin{author} + author: + - \format[Authors(LastFirst, MiddleInitial, Sep =\n - , LastSep =\n - )]{\author} +\end{author} +\begin{date} date: \date\end{date} +\begin{editor} editor: \editor\end{editor} +\begin{publisher} publisher: \publisher\end{publisher} +\begin{address} location: \address\end{address} +\begin{institution} organization: \institution\end{institution} +\begin{volume} volume: \volume\end{volume} +\begin{edition} edition: \edition\end{edition} +\begin{pages} page-range: \pages\end{pages} +\begin{url} url: \url\end{url} +\begin{doi} doi: "\doi"\end{doi} +\begin{isbn} isbn: \isbn\end{isbn} +\begin{issn} issn: \issn\end{issn} +\begin{note} note: \note\end{note} + diff --git a/src/test/java/org/jabref/logic/exporter/HayagrivaYamlExporterTest.java b/src/test/java/org/jabref/logic/exporter/HayagrivaYamlExporterTest.java new file mode 100644 index 00000000000..7a058ec059d --- /dev/null +++ b/src/test/java/org/jabref/logic/exporter/HayagrivaYamlExporterTest.java @@ -0,0 +1,186 @@ +package org.jabref.logic.exporter; + +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Collections; +import java.util.List; + +import org.jabref.logic.layout.LayoutFormatterPreferences; +import org.jabref.logic.util.StandardFileType; +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.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; +import org.mockito.Answers; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.mock; + +public class HayagrivaYamlExporterTest { + + private static Exporter hayagrivaYamlExporter; + private static BibDatabaseContext databaseContext; + + @BeforeAll + static void setUp() { + hayagrivaYamlExporter = new TemplateExporter( + "Hayagriva YAML", + "hayagrivayaml", + "hayagrivayaml", + null, + StandardFileType.YAML, + mock(LayoutFormatterPreferences.class, Answers.RETURNS_DEEP_STUBS), + SaveOrder.getDefaultSaveOrder(), + BlankLineBehaviour.DELETE_BLANKS); + + databaseContext = new BibDatabaseContext(); + } + + @Test + public final void exportForNoEntriesWritesNothing(@TempDir Path tempFile) throws Exception { + Path file = tempFile.resolve("ThisIsARandomlyNamedFile"); + Files.createFile(file); + hayagrivaYamlExporter.export(databaseContext, tempFile, Collections.emptyList()); + assertEquals(Collections.emptyList(), Files.readAllLines(file)); + } + + @Test + public final void exportsCorrectContent(@TempDir Path tempFile) throws Exception { + BibEntry entry = new BibEntry(StandardEntryType.Article) + .withCitationKey("test") + .withField(StandardField.AUTHOR, "Test Author") + .withField(StandardField.TITLE, "Test Title") + .withField(StandardField.URL, "http://example.com") + .withField(StandardField.DATE, "2020-10-14"); + + Path file = tempFile.resolve("RandomFileName"); + Files.createFile(file); + hayagrivaYamlExporter.export(databaseContext, file, Collections.singletonList(entry)); + + List expected = List.of( + "---", + "test:", + " type: article", + " title: \"Test Title\"", + " author:", + " - Author, Test", + " date: 2020-10-14", + " url: http://example.com", + "---"); + + assertEquals(expected, Files.readAllLines(file)); + } + + @Test + public final void exportsCorrectMultipleAuthors(@TempDir Path tempFile) throws Exception { + BibEntry entry = new BibEntry(StandardEntryType.Article) + .withCitationKey("test") + .withField(StandardField.AUTHOR, "Test Author and Other One") + .withField(StandardField.TITLE, "Test Title") + .withField(StandardField.URL, "http://example.com") + .withField(StandardField.DATE, "2020-10-14"); + + Path file = tempFile.resolve("RandomFileName"); + Files.createFile(file); + hayagrivaYamlExporter.export(databaseContext, file, Collections.singletonList(entry)); + + List expected = List.of( + "---", + "test:", + " type: article", + " title: \"Test Title\"", + " author:", + " - Author, Test", + " - One, Other", + " date: 2020-10-14", + " url: http://example.com", + "---"); + + assertEquals(expected, Files.readAllLines(file)); + } + + @Test + public final void formatsContentCorrect(@TempDir Path tempFile) throws Exception { + BibEntry entry = new BibEntry(StandardEntryType.Misc) + .withCitationKey("test") + .withField(StandardField.AUTHOR, "Test Author") + .withField(StandardField.TITLE, "Test Title") + .withField(StandardField.URL, "http://example.com") + .withField(StandardField.DATE, "2020-10-14"); + + Path file = tempFile.resolve("RandomFileName"); + Files.createFile(file); + hayagrivaYamlExporter.export(databaseContext, file, Collections.singletonList(entry)); + + List expected = List.of( + "---", + "test:", + " type: Misc", + " title: \"Test Title\"", + " author:", + " - Author, Test", + " date: 2020-10-14", + " url: http://example.com", + "---"); + + assertEquals(expected, Files.readAllLines(file)); + } + + @Test + void passesModifiedCharset(@TempDir Path tempFile) throws Exception { + BibEntry entry = new BibEntry(StandardEntryType.Article) + .withCitationKey("test") + .withField(StandardField.AUTHOR, "谷崎 潤一郎") + .withField(StandardField.TITLE, "細雪") + .withField(StandardField.URL, "http://example.com") + .withField(StandardField.DATE, "2020-10-14"); + + Path file = tempFile.resolve("RandomFileName"); + Files.createFile(file); + hayagrivaYamlExporter.export(databaseContext, file, Collections.singletonList(entry)); + + List expected = List.of( + "---", + "test:", + " type: article", + " title: \"細雪\"", + " author:", + " - 潤一郎, 谷崎", + " date: 2020-10-14", + " url: http://example.com", + "---"); + + assertEquals(expected, Files.readAllLines(file)); + } + + @Test + void passesModifiedCharsetNull(@TempDir Path tempFile) throws Exception { + BibEntry entry = new BibEntry(StandardEntryType.Article) + .withCitationKey("test") + .withField(StandardField.AUTHOR, "谷崎 潤一郎") + .withField(StandardField.TITLE, "細雪") + .withField(StandardField.URL, "http://example.com") + .withField(StandardField.DATE, "2020-10-14"); + + Path file = tempFile.resolve("RandomFileName"); + Files.createFile(file); + hayagrivaYamlExporter.export(databaseContext, file, Collections.singletonList(entry)); + + List expected = List.of( + "---", + "test:", + " type: article", + " title: \"細雪\"", + " author:", + " - 潤一郎, 谷崎", + " date: 2020-10-14", + " url: http://example.com", + "---"); + assertEquals(expected, Files.readAllLines(file)); + } +}