From f2d1a034013f20286ec7be6e6dcff28fa6ec863b Mon Sep 17 00:00:00 2001 From: Cherrie Chang Date: Wed, 18 Dec 2024 08:02:49 -0500 Subject: [PATCH] fix citation logic --- .gitignore | 1 + packages/config/generateCitations.js | 13 ++-- packages/jspsych/src/JsPsych.ts | 42 +++++++------ .../jspsych/tests/citations/citations.test.ts | 62 +++++++++++-------- 4 files changed, 67 insertions(+), 51 deletions(-) diff --git a/.gitignore b/.gitignore index b9e6aaaf..5cf5157d 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ coverage/ dist.zip packages/jspsych/README.md .turbo +.env diff --git a/packages/config/generateCitations.js b/packages/config/generateCitations.js index 5c872481..9b4dbdad 100644 --- a/packages/config/generateCitations.js +++ b/packages/config/generateCitations.js @@ -21,19 +21,22 @@ export default function generateCitations() { // Try to find CITATION.cff file and look for preferred-citation const citationCff = (() => { let rawCff; - try { - // look for CITATION.cff in the current directory - rawCff = fs.readFileSync("./CITATION.cff", "utf-8").toString(); + const getCff = (path) => { + rawCff = fs.readFileSync(path, "utf-8").toString(); const cffData = yaml.parse(rawCff); if (cffData["preferred-citation"]) { preferredCitation = true; } return yaml.stringify(rawCff); + }; + + try { + // look for CITATION.cff in the current directory + return getCff("./CITATION.cff"); } catch (error) { try { // look for CITATION.cff in the root of the repository - rawCff = fs.readFileSync(path.join(appRootPath.path, "CITATION.cff"), "utf-8").toString(); - return yaml.stringify(rawCff); + return getCff(path.join(appRootPath.path, "CITATION.cff")); } catch (error) { console.warn( `No CITATION.cff file found: ${error.message}. If you would like to include a citation, please create a CITATION.cff file in the root of your repository.` diff --git a/packages/jspsych/src/JsPsych.ts b/packages/jspsych/src/JsPsych.ts index f89f7ef2..0f403209 100644 --- a/packages/jspsych/src/JsPsych.ts +++ b/packages/jspsych/src/JsPsych.ts @@ -262,33 +262,35 @@ export class JsPsych { } getCitations( - plugins: Array> | Class>, - format?: string + plugins: Array> | Class> = [], + format: "apa" | "bibtex" = "apa" ) { - format = format ? format.toLowerCase() : "apa"; + const formatOptions = ["apa", "bibtex"]; + const jsPsychCitations: any = "__CITATIONS__"; + format = format.toLowerCase() as "apa" | "bibtex"; // Check if plugins is an array if (!Array.isArray(plugins)) { throw new Error("Expected array of plugins/extensions"); } - // Check if array is empty - else if (plugins.length == 0) { - console.log( - format == "apa" - ? "de Leeuw, J. R., Gilbert, R. A., & Luchterhandt, B. (2023). jsPsych: Enabling an Open-Source Collaborative Ecosystem of Behavioral Experiments. Journal of Open Source Software, 8(85), 5351. https://doi.org/10.21105/joss.05351 " - : '@article{Leeuw2023jsPsych, author = {de Leeuw, Joshua R. and Gilbert, Rebecca A. and Luchterhandt, Bj{\\" o}rn}, journal = {Journal of Open Source Software}, doi = {10.21105/joss.05351}, issn = {2475-9066}, number = {85}, year = {2023}, month = {may 11}, pages = {5351}, publisher = {Open Journals}, title = {jsPsych: Enabling an {Open}-{Source} {Collaborative} {Ecosystem} of {Behavioral} {Experiments}}, url = {https://joss.theoj.org/papers/10.21105/joss.05351}, volume = {8}, } ' - ); - return; - } // Check if format is supported - else if (!Object.keys(plugins[0]["info"].citations).includes(format)) { + else if (!formatOptions.includes(format)) { throw new Error("Unsupported citation format"); - } else { - const pluginsSet = new Set(plugins); - plugins = Array.from(pluginsSet); - plugins.map((plugin) => { - let pluginCitations = plugin["info"].citations; - console.log(format == "apa" ? `${pluginCitations.apa}` : `${pluginCitations.bibtex}`); - }); + } + // Print citations + else { + const jsPsychCitation = jsPsychCitations[format]; + const citationSet = new Set([jsPsychCitation]); + + for (const plugin of plugins) { + try { + const pluginCitation = plugin["info"].citations[format]; + citationSet.add(pluginCitation); + } catch { + console.error(`${plugin} does not have citation in ${format} format.`); + } + } + const citationList = Array.from(citationSet).join("\n"); + return citationList; } } diff --git a/packages/jspsych/tests/citations/citations.test.ts b/packages/jspsych/tests/citations/citations.test.ts index 1841a3d9..63202f9d 100644 --- a/packages/jspsych/tests/citations/citations.test.ts +++ b/packages/jspsych/tests/citations/citations.test.ts @@ -1,50 +1,55 @@ -import { JsPsych } from "../../src/JsPsych"; +import { initJsPsych } from "../../dist/index.js"; import { TestExtension } from "../extensions/TestExtension"; import TestPlugin from "../TestPlugin"; +const jsPsychApaCitation = + "de Leeuw, J. R., Gilbert, R. A., & Luchterhandt, B. (2023). jsPsych: Enabling an Open-Source Collaborative Ecosystem of Behavioral Experiments. Journal of Open Source Software, 8(85), 5351. https://doi.org/10.21105/joss.05351"; +const jsPsychBibtexCitation = + '@misc{LeeuwjsPsych, author = {de Leeuw, Joshua R. and Gilbert, Rebecca A. and Luchterhandt, Bj{\\" o}rn}, doi = {10.5281/zenodo.7702307}, title = {jsPsych: Enabling an {Open}-{Source} {Collaborative} {Ecosystem} of {Behavioral} {Experiments}}, } @article{Leeuw2023jsPsych, author = {de Leeuw, Joshua R. and Gilbert, Rebecca A. and Luchterhandt, Bj{\\" o}rn}, journal = {Journal of Open Source Software}, doi = {10.21105/joss.05351}, issn = {2475-9066}, number = {85}, year = {2023}, month = {may 11}, pages = {5351}, publisher = {Open Journals}, title = {jsPsych: Enabling an {Open}-{Source} {Collaborative} {Ecosystem} of {Behavioral} {Experiments}}, url = {https://joss.theoj.org/papers/10.21105/joss.05351}, volume = {8}, } '; const testPluginApaCitation = "Test plugin APA citation"; const testPluginBibtexCitation = "Test plugin BibTeX citation"; const testExtensionApaCitation = "Test extension APA citation"; -let jspsych: JsPsych; -let consoleLogSpy: jest.SpyInstance; -let consoleWarnSpy: jest.SpyInstance; - +let jsPsych; beforeEach(() => { - jspsych = new JsPsych(); - consoleLogSpy = jest.spyOn(console, "log").mockImplementation(); - consoleWarnSpy = jest.spyOn(console, "warn").mockImplementation(); -}); - -afterEach(() => { - jest.restoreAllMocks(); + jsPsych = initJsPsych(); }); describe("citing not using an array", () => { test("citing nothing", () => { - expect(() => jspsych.getCitations(null)).toThrow("Expected array of plugins/extensions"); + const citation = jsPsych.getCitations(); + console.log(citation); + expect(citation).toMatch(jsPsychApaCitation); + }); + test("citing without input and with valid format", () => { + jsPsych.getCitations(null, "apa"); + expect(consoleLogSpy.mock.calls).toHaveLength(1); + expect(consoleLogSpy.mock.calls[0][0]).toBe(jsPsychApaCitation); }); test("citing without input and with invalid format", () => { - expect(() => jspsych.getCitations(null, "apa")).toThrow("Expected array of plugins/extensions"); + expect(() => jspsych.getCitations(null, "dummyTex")).toThrow("Unsupported citation format"); }); }); describe("citing using an array in different formats", () => { test("citing empty array with APA format", () => { jspsych.getCitations([], "apa"); - expect(consoleWarnSpy.mock.calls[0][0]).toBe("No plugins/extensions provided"); + expect(consoleLogSpy.mock.calls).toHaveLength(1); + expect(consoleLogSpy.mock.calls[0][0]).toBe(jsPsychApaCitation); }); test("citing empty array with BibTeX format", () => { jspsych.getCitations([], "bibtex"); - expect(consoleWarnSpy.mock.calls[0][0]).toBe("No plugins/extensions provided"); + expect(consoleLogSpy.mock.calls).toHaveLength(1); + expect(consoleLogSpy.mock.calls[0][0]).toBe(jsPsychBibtexCitation); }); test("citing empty array without format", () => { jspsych.getCitations([]); - expect(consoleWarnSpy.mock.calls[0][0]).toBe("No plugins/extensions provided"); + expect(consoleLogSpy.mock.calls).toHaveLength(1); + expect(consoleLogSpy.mock.calls[0][0]).toBe(jsPsychApaCitation); }); test("citing one plugin with valid format in all caps", () => { - jspsych.getCitations([TestPlugin], "APA"); - expect(consoleLogSpy.mock.calls[0][0]).toBe(testPluginApaCitation); + const citation = jsPsych.getCitations([TestPlugin], "APA"); + expect(citation).toBe(jsPsychApaCitation + "\n" + testPluginApaCitation + "\n"); }); test("citing with unsupported format", () => { expect(() => jspsych.getCitations([TestPlugin], "DummyTex")).toThrow( @@ -56,22 +61,27 @@ describe("citing using an array in different formats", () => { describe("citing mix of valid plugins/extensions", () => { test("citing a plugin", () => { jspsych.getCitations([TestPlugin]); - expect(consoleLogSpy.mock.calls[0][0]).toBe(testPluginApaCitation); + expect(consoleLogSpy.mock.calls).toHaveLength(2); + // expect(consoleLogSpy.mock.calls[0][0]).toBe(jsPsychApaCitation); + expect(consoleLogSpy.mock.calls[1][0]).toBe(testPluginApaCitation); }); test("citing a plugin in BibTeX", () => { jspsych.getCitations([TestPlugin], "bibtex"); - expect(consoleLogSpy.mock.calls[0][0]).toBe(testPluginBibtexCitation); + expect(consoleLogSpy.mock.calls).toHaveLength(2); + expect(consoleLogSpy.mock.calls[0][0]).toBe(jsPsychBibtexCitation); + expect(consoleLogSpy.mock.calls[1][0]).toBe(testPluginBibtexCitation); }); - test("citing multiple plugins", () => { + test("citing multiple of the same plugins", () => { jspsych.getCitations([TestPlugin, TestPlugin]); expect(consoleLogSpy.mock.calls).toHaveLength(2); - expect(consoleLogSpy.mock.calls[0][0]).toBe(testPluginApaCitation); + expect(consoleLogSpy.mock.calls[0][0]).toBe(jsPsychApaCitation); expect(consoleLogSpy.mock.calls[1][0]).toBe(testPluginApaCitation); }); test("citing mix of plugins and extensions", () => { jspsych.getCitations([TestPlugin, TestExtension]); - expect(consoleLogSpy.mock.calls).toHaveLength(2); - expect(consoleLogSpy.mock.calls[0][0]).toBe(testPluginApaCitation); - expect(consoleLogSpy.mock.calls[1][0]).toBe(testExtensionApaCitation); + expect(consoleLogSpy.mock.calls).toHaveLength(3); + expect(consoleLogSpy.mock.calls[0][0]).toBe(jsPsychApaCitation); + expect(consoleLogSpy.mock.calls[1][0]).toBe(testPluginApaCitation); + expect(consoleLogSpy.mock.calls[2][0]).toBe(testExtensionApaCitation); }); });