Merge pull request #3385 from jspsych/add-citation-module

Generate citation strings from citation.cff file as part of build process
This commit is contained in:
Josh de Leeuw 2024-12-18 17:36:02 -05:00 committed by GitHub
commit 2ddc120bed
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
74 changed files with 5251 additions and 3640 deletions

View File

@ -0,0 +1,62 @@
---
"@jspsych/plugin-serial-reaction-time-mouse": minor
"@jspsych/plugin-canvas-keyboard-response": minor
"@jspsych/plugin-audio-keyboard-response": minor
"@jspsych/plugin-image-keyboard-response": minor
"@jspsych/plugin-video-keyboard-response": minor
"@jspsych/plugin-canvas-button-response": minor
"@jspsych/plugin-canvas-slider-response": minor
"@jspsych/plugin-html-keyboard-response": minor
"@jspsych/plugin-audio-button-response": minor
"@jspsych/plugin-audio-slider-response": minor
"@jspsych/plugin-image-button-response": minor
"@jspsych/plugin-image-slider-response": minor
"@jspsych/plugin-initialize-microphone": minor
"@jspsych/plugin-video-button-response": minor
"@jspsych/plugin-video-slider-response": minor
"@jspsych/plugin-categorize-animation": minor
"@jspsych/plugin-html-button-response": minor
"@jspsych/plugin-html-slider-response": minor
"@jspsych/plugin-same-different-image": minor
"@jspsych/plugin-serial-reaction-time": minor
"@jspsych/plugin-visual-search-circle": minor
"@jspsych/plugin-webgazer-init-camera": minor
"@jspsych/plugin-html-audio-response": minor
"@jspsych/plugin-html-video-response": minor
"@jspsych/plugin-same-different-html": minor
"@jspsych/plugin-survey-multi-choice": minor
"@jspsych/plugin-survey-multi-select": minor
"@jspsych/plugin-webgazer-calibrate": minor
"@jspsych/extension-mouse-tracking": minor
"@jspsych/plugin-initialize-camera": minor
"@jspsych/plugin-webgazer-validate": minor
"@jspsych/plugin-categorize-image": minor
"@jspsych/plugin-survey-html-form": minor
"@jspsych/plugin-virtual-chinrest": minor
"@jspsych/extension-record-video": minor
"@jspsych/plugin-categorize-html": minor
"@jspsych/plugin-reconstruction": minor
"@jspsych/plugin-browser-check": minor
"@jspsych/plugin-call-function": minor
"@jspsych/plugin-external-html": minor
"@jspsych/plugin-mirror-camera": minor
"@jspsych/plugin-survey-likert": minor
"@jspsych/plugin-instructions": minor
"@jspsych/extension-webgazer": minor
"@jspsych/plugin-survey-text": minor
"@jspsych/plugin-fullscreen": minor
"@jspsych/plugin-animation": minor
"@jspsych/plugin-free-sort": minor
"@jspsych/plugin-iat-image": minor
"@jspsych/plugin-sketchpad": minor
"@jspsych/plugin-iat-html": minor
"@jspsych/plugin-maxdiff": minor
"@jspsych/plugin-preload": minor
"@jspsych/plugin-resize": minor
"@jspsych/plugin-survey": minor
"@jspsych/plugin-cloze": minor
"jspsych": minor
"@jspsych/config": minor
---
Added citations property to info field of all plugins/extensions in two citation formats (apa, bibtex); added getCitations() as function in jsPsych package allowing user to generate citations by passing an array of plugins/extensions by name as first input and citation format as string as second input; changed template of plugins/extensions to contain citations field by default; citations for each plugin/extension are automatically generated from .cff file (if any) at its folder's root during build process; getCitations() prints out citations in the form of a string separating each citation with newline character, and always prints the jsPsych library citation first.

1
.gitignore vendored
View File

@ -11,3 +11,4 @@ coverage/
dist.zip dist.zip
packages/jspsych/README.md packages/jspsych/README.md
.turbo .turbo
.env

View File

@ -8,10 +8,20 @@ jsPsych was created by [Josh de Leeuw](https://www.vassar.edu/faculty/jdeleeuw).
If you use this library in academic work, the preferred citation is: If you use this library in academic work, the preferred citation is:
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://joss.theoj.org/papers/10.21105/joss.05351](https://joss.theoj.org/papers/10.21105/joss.05351). > 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://joss.theoj.org/papers/10.21105/joss.05351](https://joss.theoj.org/papers/10.21105/joss.05351).
This paper is an updated description of jsPsych and includes all current core team members. It replaces the earlier paper that described jsPsych: This paper is an updated description of jsPsych and includes all current core team members. It replaces the earlier paper that described jsPsych:
de Leeuw, J.R. (2015). jsPsych: A JavaScript library for creating behavioral experiments in a Web browser. *Behavior Research Methods*, _47_(1), 1-12. doi:[10.3758/s13428-014-0458-y](http://link.springer.com/article/10.3758%2Fs13428-014-0458-y) > de Leeuw, J.R. (2015). jsPsych: A JavaScript library for creating behavioral experiments in a Web browser. *Behavior Research Methods*, _47_(1), 1-12. doi:[10.3758/s13428-014-0458-y](http://link.springer.com/article/10.3758%2Fs13428-014-0458-y)
Citations help us demonstrate that this library is used and valued, which allows us to continue working on it. Citations help us demonstrate that this library is used and valued, which allows us to continue working on it.
#### Citation tool for third-party plugins/extensions
jsPsych is an open-source, collaborative ecosystem, and many of the plugins/extensions you end up using may be contributed by third-party developers! We want to make sure they get recognition for their good work, so we made a command-line citation tool that you should use to cite this library and the plugins/extensions used in your experiment. You can see this tool in action by following these steps:
1. Launch a jsPsych experiment in your browser
2. Open up the browser console using Ctrl + ⇧ + J (Windows) or ⌘ + ⌥ + J (Mac)
3. Type `jsPsych.getCitations()`
This should print the APA format citation for the jsPsych library, which you can then copy and paste into your working document. To cite the plugins/extensions in your experiment, you should pass in an array containing the name of each plugin/extension to generate a list of citations, e.g. `jsPsych.getCitations([jsPsychHtmlKeyboardResponse, jsPsychMouseTrackingExtension])`. You can also pass in the desired output citation format as the second argument, e.g. `jsPsych.getCitations([jsPsychHtmlKeyboardResponse, jsPsychMouseTrackingExtension], "apa")`. We currently support APA formatting (`"apa"`) and BibTex formatting (`"bibtex"`).

View File

@ -20,6 +20,8 @@ We welcome contributions of any scope. Before we can merge changes into the main
* **An example file should be included if applicable.** If you are contributing a new feature, new plugin, or new extension, or contributing a modification that changes the behavior of the library in some important way, consider adding an example file to the `/examples` folder in the repository. * **An example file should be included if applicable.** If you are contributing a new feature, new plugin, or new extension, or contributing a modification that changes the behavior of the library in some important way, consider adding an example file to the `/examples` folder in the repository.
* **If you are contributing a plugin/extension, we strongly encourage including a file containing citation information.** This file should be named `CITATION.cff` and placed at the root of your repository. This allows people who use your plugin/extension in their code to easily cite your work by calling `jsPsych.getCitations([<yourPlugin>])` from their command line. More information on `.cff` files can be found [here](https://citation-file-format.github.io/).
* **A changeset must be included in the pull request**. We use [changesets](https://github.com/atlassian/changesets/blob/main/docs/adding-a-changeset.md) to generate new releases and their corresponding release notes. [This is a good overview of changesets](https://github.com/atlassian/changesets/blob/main/docs/adding-a-changeset.md) that explains how to add one to your pull request. Feel free to ask for help with this! * **A changeset must be included in the pull request**. We use [changesets](https://github.com/atlassian/changesets/blob/main/docs/adding-a-changeset.md) to generate new releases and their corresponding release notes. [This is a good overview of changesets](https://github.com/atlassian/changesets/blob/main/docs/adding-a-changeset.md) that explains how to add one to your pull request. Feel free to ask for help with this!
* **Update the contributors.md file**. If you are a first time contributor to jsPsych please add your name to our [contributors file](https://github.com/jspsych/jsPsych/blob/main/contributors.md). And thanks! * **Update the contributors.md file**. If you are a first time contributor to jsPsych please add your name to our [contributors file](https://github.com/jspsych/jsPsych/blob/main/contributors.md). And thanks!

View File

@ -346,6 +346,34 @@ This method tells jsPsych that the current trial is over. It is used in all of t
jsPsych.finishTrial({correct_response: true}); jsPsych.finishTrial({correct_response: true});
``` ```
---
## jsPsych.getCitations
```javascript
jsPsych.getCitations(plugins, format)
```
### Parameters
| Parameter | Type | Description |
| --------- | ------ | ---------------------------------------------------- |
| plugins | array | Array containing list of plugins/extensions by name. |
| format | string | Output citation format ("apa" | "bibtex") |
### Return value
String of generated citations in the specified format for the jsPsych library, followed by that for each input plugin/extension, separated with a "\n" character.
### Description
Get citations in a specified format for the jsPsych library and input list of plugins/extensions, usually those used within an experiment.
### Example
```javascript
// in browser console
jsPsych.getCitations() // prints citation for jsPsych library in APA format
jsPsych.getCitations([TestPlugin], "bibtex") // prints citation for jsPsych library and TestPlugin (if different) in BibTex format
```
--- ---
## jsPsych.getCurrentTrial ## jsPsych.getCurrentTrial

8361
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -27,8 +27,8 @@
"devDependencies": { "devDependencies": {
"@changesets/changelog-github": "^0.4.7", "@changesets/changelog-github": "^0.4.7",
"@changesets/cli": "^2.25.2", "@changesets/cli": "^2.25.2",
"@jspsych/config": "^1.3.2", "@jspsych/config": "^3.0.0",
"husky": "^8.0.2", "husky": "^8.0.3",
"import-sort-style-module": "^6.0.0", "import-sort-style-module": "^6.0.0",
"lint-staged": "^13.0.3", "lint-staged": "^13.0.3",
"prettier": "^2.7.1", "prettier": "^2.7.1",

View File

@ -0,0 +1,94 @@
import "@citation-js/plugin-bibtex";
import "@citation-js/plugin-software-formats";
import "@citation-js/plugin-csl";
import fs from "node:fs";
import path from "node:path";
import { Cite } from "@citation-js/core";
import appRootPath from "app-root-path";
import yaml from "yaml";
/**
* Generate citation data from CITATION.cff file
* Currently supported formats: APA, BibTeX
*
* @returns {Object} - Object containing APA and BibTeX formatted citation data
*/
export default function generateCitations() {
let preferredCitation = false;
// Try to find CITATION.cff file and look for preferred-citation
const citationCff = (() => {
let rawCff;
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
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.`
);
return null;
}
}
})();
if (!citationCff) {
return { apa: "", bibtex: "" };
}
// Convert CITATION.cff to APA string
const citationApa = (() => {
try {
const apaCite = new Cite(citationCff);
apaCite["data"] = preferredCitation ? apaCite["data"].slice(1) : apaCite["data"];
const citationApa = apaCite.format("bibliography", {
format: "text",
template: "apa",
lang: "en-us",
});
return citationApa;
} catch (error) {
console.log(`Error converting CITATION.cff to APA string: ${error.message}`);
return "";
}
})();
// Convert CITATION.cff to BibTeX string
const citationBibtex = (() => {
try {
const bibtexCite = new Cite(citationCff);
bibtexCite["data"] = preferredCitation ? bibtexCite["data"].slice(1) : bibtexCite["data"];
const citationBibtex = bibtexCite.format("bibtex", {
format: "text",
template: "bibtex",
lang: "en-us",
});
return citationBibtex;
} catch (error) {
console.log(`Error converting CITATION.cff to BibTeX string: ${error.message}`);
return null;
}
})();
// Return formatted citation data
const citationData = {
apa: citationApa.replace(/\n/g, " "),
bibtex: citationBibtex.replace(/\n/g, " "),
};
return citationData;
}

View File

@ -35,12 +35,18 @@
}, },
"homepage": "https://www.jspsych.org/latest/developers/configuration", "homepage": "https://www.jspsych.org/latest/developers/configuration",
"dependencies": { "dependencies": {
"@citation-js/core": "^0.7.14",
"@citation-js/plugin-bibtex": "^0.7.14",
"@citation-js/plugin-csl": "^0.7.14",
"@citation-js/plugin-software-formats": "^0.6.1",
"@rollup/plugin-commonjs": "26.0.1", "@rollup/plugin-commonjs": "26.0.1",
"@rollup/plugin-node-resolve": "15.2.3", "@rollup/plugin-node-resolve": "15.2.3",
"@rollup/plugin-replace": "^6.0.1",
"@sucrase/jest-plugin": "3.0.0", "@sucrase/jest-plugin": "3.0.0",
"@types/gulp": "4.0.17", "@types/gulp": "4.0.17",
"@types/jest": "29.5.8", "@types/jest": "29.5.8",
"alias-hq": "6.2.4", "alias-hq": "6.2.4",
"app-root-path": "^3.1.0",
"canvas": "^2.11.2", "canvas": "^2.11.2",
"esbuild": "0.23.1", "esbuild": "0.23.1",
"gulp": "5.0.0", "gulp": "5.0.0",
@ -55,9 +61,11 @@
"rollup": "4.21.2", "rollup": "4.21.2",
"rollup-plugin-dts": "6.1.1", "rollup-plugin-dts": "6.1.1",
"rollup-plugin-esbuild": "6.1.1", "rollup-plugin-esbuild": "6.1.1",
"rollup-plugin-modify": "^3.0.0",
"rollup-plugin-node-externals": "7.1.3", "rollup-plugin-node-externals": "7.1.3",
"sucrase": "3.34.0", "sucrase": "3.34.0",
"tslib": "2.6.2", "tslib": "2.6.2",
"typescript": "^5.2.2" "typescript": "^5.2.2",
"yaml": "^2.5.1"
} }
} }

View File

@ -6,9 +6,12 @@ import resolve from "@rollup/plugin-node-resolve";
import { defineConfig } from "rollup"; import { defineConfig } from "rollup";
import dts from "rollup-plugin-dts"; import dts from "rollup-plugin-dts";
import esbuild from "rollup-plugin-esbuild"; import esbuild from "rollup-plugin-esbuild";
import modify from "rollup-plugin-modify";
import externals from "rollup-plugin-node-externals"; import externals from "rollup-plugin-node-externals";
import ts from "typescript"; import ts from "typescript";
import generateCitations from "./generateCitations.js";
const getTsCompilerOptions = () => { const getTsCompilerOptions = () => {
const cwd = process.cwd(); const cwd = process.cwd();
return ts.parseJsonConfigFileContent( return ts.parseJsonConfigFileContent(
@ -38,6 +41,8 @@ const makeConfig = ({
...outputOptions, ...outputOptions,
}; };
const citationData = generateCitations();
/** @type{import("rollup-plugin-esbuild").Options} */ /** @type{import("rollup-plugin-esbuild").Options} */
const esBuildPluginOptions = { const esBuildPluginOptions = {
loaders: { ".json": "json" }, loaders: { ".json": "json" },
@ -71,6 +76,11 @@ const makeConfig = ({
input, input,
plugins: [ plugins: [
externals(), externals(),
modify({
// prettier-ignore
find: /'__CITATIONS__'/g,
replace: JSON.stringify(citationData, null, 2),
}),
esbuild({ ...esBuildPluginOptions, target: "node18" }), esbuild({ ...esBuildPluginOptions, target: "node18" }),
commonjs(commonjsPluginOptions), commonjs(commonjsPluginOptions),
], ],
@ -96,6 +106,11 @@ const makeConfig = ({
input, input,
plugins: [ plugins: [
externals({ deps: false }), externals({ deps: false }),
modify({
// prettier-ignore
find: /'__CITATIONS__'/g,
replace: JSON.stringify(citationData, null, 2),
}),
resolve({ preferBuiltins: false }), resolve({ preferBuiltins: false }),
esbuild({ ...esBuildPluginOptions, target: "esnext" }), esbuild({ ...esBuildPluginOptions, target: "esnext" }),
commonjs(commonjsPluginOptions), commonjs(commonjsPluginOptions),
@ -115,6 +130,11 @@ const makeConfig = ({
input, input,
plugins: [ plugins: [
externals({ deps: false }), externals({ deps: false }),
modify({
// prettier-ignore
find: /'__CITATIONS__'/g,
replace: JSON.stringify(citationData, null, 2),
}),
resolve({ preferBuiltins: false }), resolve({ preferBuiltins: false }),
esbuild({ ...esBuildPluginOptions, target: "es2015", minify: true }), esbuild({ ...esBuildPluginOptions, target: "es2015", minify: true }),
commonjs(commonjsPluginOptions), commonjs(commonjsPluginOptions),
@ -164,8 +184,9 @@ export const makeCoreRollupConfig = () =>
/** /**
* Returns the rollup configuration for Node.js-only packages * Returns the rollup configuration for Node.js-only packages
*/ */
export const makeNodeRollupConfig = () => export const makeNodeRollupConfig = () => {
makeConfig({ return makeConfig({
globalOptions: { external: ["jspsych"] }, globalOptions: { external: ["jspsych"] },
isNodeOnlyBuild: true, isNodeOnlyBuild: true,
}); });
};

View File

@ -95,6 +95,8 @@ class MouseTrackingExtension implements JsPsychExtension {
}, },
}, },
}, },
// prettier-ignore
citations: '__CITATIONS__',
}; };
constructor(private jsPsych: JsPsych) {} constructor(private jsPsych: JsPsych) {}

View File

@ -16,6 +16,8 @@ class RecordVideoExtension implements JsPsychExtension {
type: ParameterType.STRING, type: ParameterType.STRING,
}, },
}, },
// prettier-ignore
citations: '__CITATIONS__',
}; };
constructor(private jsPsych: JsPsych) { constructor(private jsPsych: JsPsych) {

View File

@ -91,6 +91,8 @@ class WebGazerExtension implements JsPsychExtension {
}, },
}, },
}, },
// prettier-ignore
citations: '__CITATIONS__',
}; };
constructor(private jsPsych: JsPsych) {} constructor(private jsPsych: JsPsych) {}

View File

@ -1,6 +1,6 @@
import { Class } from "type-fest"; import { Class } from "type-fest";
import { TestExtension } from "../tests/extensions/test-extension"; import { TestExtension } from "../tests/extensions/TestExtension";
import { ExtensionManager, ExtensionManagerDependencies } from "./ExtensionManager"; import { ExtensionManager, ExtensionManagerDependencies } from "./ExtensionManager";
import { JsPsych } from "./JsPsych"; import { JsPsych } from "./JsPsych";
import { JsPsychExtension } from "./modules/extensions"; import { JsPsychExtension } from "./modules/extensions";

View File

@ -1,9 +1,13 @@
import autoBind from "auto-bind"; import autoBind from "auto-bind";
// To work with citations
import { Class } from "type-fest";
import { version } from "../package.json"; import { version } from "../package.json";
import { ExtensionManager, ExtensionManagerDependencies } from "./ExtensionManager"; import { ExtensionManager, ExtensionManagerDependencies } from "./ExtensionManager";
import { JsPsychData, JsPsychDataDependencies } from "./modules/data"; import { JsPsychData, JsPsychDataDependencies } from "./modules/data";
import { JsPsychExtension } from "./modules/extensions";
import { PluginAPI, createJointPluginAPIObject } from "./modules/plugin-api"; import { PluginAPI, createJointPluginAPIObject } from "./modules/plugin-api";
import { JsPsychPlugin } from "./modules/plugins";
import * as randomization from "./modules/randomization"; import * as randomization from "./modules/randomization";
import * as turk from "./modules/turk"; import * as turk from "./modules/turk";
import * as utils from "./modules/utils"; import * as utils from "./modules/utils";
@ -257,6 +261,48 @@ export class JsPsych {
return this.timeline?.description.timeline; return this.timeline?.description.timeline;
} }
/**
* Prints out a string containing citations for the jsPsych library and all input plugins/extensions in the specified format.
* If called without input, prints citation for jsPsych library.
*
* @param plugins The plugins/extensions to generate citations for. Always prints the citation for the jsPsych library at the top.
* @param format The desired output citation format. Currently supports "apa" and "bibtex".
* @returns String containing citations separated with newline character.
*/
getCitations(
plugins: Array<Class<JsPsychPlugin<any>> | Class<JsPsychExtension>> = [],
format: "apa" | "bibtex" = "apa"
) {
const formatOptions = ["apa", "bibtex"];
// prettier-ignore
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 format is supported
else if (!formatOptions.includes(format)) {
throw new Error("Unsupported citation format");
}
// 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;
}
}
get extensions() { get extensions() {
return this.extensionManager?.extensions ?? {}; return this.extensionManager?.extensions ?? {};
} }

View File

@ -4,6 +4,7 @@ export interface JsPsychExtensionInfo {
name: string; name: string;
version?: string; version?: string;
data?: ParameterInfos; data?: ParameterInfos;
citations?: Record<string, string> | string;
} }
export interface JsPsychExtension { export interface JsPsychExtension {

View File

@ -141,6 +141,7 @@ export interface PluginInfo {
version?: string; version?: string;
parameters: ParameterInfos; parameters: ParameterInfos;
data?: ParameterInfos; data?: ParameterInfos;
citations?: Record<string, string> | string;
} }
export interface JsPsychPlugin<I extends PluginInfo> { export interface JsPsychPlugin<I extends PluginInfo> {

View File

@ -10,6 +10,10 @@ export const testPluginInfo = <const>{
version: "0.0.1", version: "0.0.1",
parameters: {}, parameters: {},
data: {}, data: {},
citations: {
apa: "Test plugin APA citation",
bibtex: "Test plugin BibTeX citation",
},
}; };
class TestPlugin implements JsPsychPlugin<typeof testPluginInfo> { class TestPlugin implements JsPsychPlugin<typeof testPluginInfo> {

View File

@ -0,0 +1,94 @@
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 =
'@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;
/**
* These tests are skipped if the built version of JsPsych is not found.
* This is because the citation functionality is only available in the built version
* due to code injections that run during the build.
*/
try {
// Try to import built version
JsPsych = require("../../dist/index").JsPsych;
let jspsych: typeof JsPsych;
beforeEach(() => {
jspsych = new JsPsych();
});
describe("citing not using an array", () => {
test("citing without input", () => {
expect(jspsych.getCitations()).toBe(jsPsychApaCitation);
});
test("citing null", () => {
expect(() => jspsych.getCitations(null)).toThrow("Expected array of plugins/extensions");
});
test("citing without input and with invalid format", () => {
expect(() => jspsych.getCitations(null, "apa")).toThrow(
"Expected array of plugins/extensions"
);
});
});
describe("citing using an array in different formats", () => {
test("citing empty array with APA format", () => {
expect(jspsych.getCitations([], "apa")).toBe(jsPsychApaCitation);
});
test("citing empty array with BibTeX format", () => {
expect(jspsych.getCitations([], "bibtex")).toBe(jsPsychBibtexCitation);
});
test("citing empty array without format", () => {
expect(jspsych.getCitations([])).toBe(jsPsychApaCitation);
});
test("citing one plugin with valid format in all caps", () => {
expect(jspsych.getCitations([TestPlugin], "APA")).toBe(
jsPsychApaCitation + "\n" + testPluginApaCitation
);
});
test("citing with unsupported format", () => {
expect(() => jspsych.getCitations([TestPlugin], "DummyTex")).toThrow(
"Unsupported citation format"
);
});
});
describe("citing mix of valid plugins/extensions", () => {
test("citing a plugin", () => {
expect(jspsych.getCitations([TestPlugin])).toBe(
jsPsychApaCitation + "\n" + testPluginApaCitation
);
});
test("citing a plugin in BibTeX", () => {
expect(jspsych.getCitations([TestPlugin], "bibtex")).toBe(
jsPsychBibtexCitation + "\n" + testPluginBibtexCitation
);
});
test("citing multiple plugins", () => {
expect(jspsych.getCitations([TestPlugin, TestPlugin])).toBe(
jsPsychApaCitation + "\n" + testPluginApaCitation
);
});
test("citing mix of plugins and extensions", () => {
expect(jspsych.getCitations([TestPlugin, TestExtension])).toBe(
jsPsychApaCitation + "\n" + testPluginApaCitation + "\n" + testExtensionApaCitation
);
});
});
} catch (e) {
// Fall back to development version if built version not found
describe("skipping citation tests because of missing built version", () => {
test.skip("skip", () => {
expect(true).toBe(true);
});
});
}

View File

@ -5,6 +5,10 @@ export class TestExtension implements JsPsychExtension {
name: "test", name: "test",
version: "0.0.1", version: "0.0.1",
data: {}, data: {},
citations: {
apa: "Test extension APA citation",
bibtex: "Test extension BibTeX citation",
},
}; };
constructor(private jsPsych: JsPsych) {} constructor(private jsPsych: JsPsych) {}

View File

@ -2,7 +2,7 @@ import htmlKeyboardResponse from "@jspsych/plugin-html-keyboard-response";
import { pressKey, startTimeline } from "@jspsych/test-utils"; import { pressKey, startTimeline } from "@jspsych/test-utils";
import { JsPsych, initJsPsych } from "../../src"; import { JsPsych, initJsPsych } from "../../src";
import { TestExtension } from "./test-extension"; import { TestExtension } from "./TestExtension";
jest.useFakeTimers(); jest.useFakeTimers();

View File

@ -96,6 +96,8 @@ const info = <const>{
}, },
}, },
}, },
// prettier-ignore
citations: '__CITATIONS__',
}; };
type Info = typeof info; type Info = typeof info;

View File

@ -114,6 +114,8 @@ const info = <const>{
type: ParameterType.INT, type: ParameterType.INT,
}, },
}, },
// prettier-ignore
citations: '__CITATIONS__',
}; };
type Info = typeof info; type Info = typeof info;

View File

@ -82,6 +82,8 @@ const info = <const>{
type: ParameterType.STRING, type: ParameterType.STRING,
}, },
}, },
// prettier-ignore
citations: '__CITATIONS__',
}; };
type Info = typeof info; type Info = typeof info;

View File

@ -117,6 +117,8 @@ const info = <const>{
type: ParameterType.INT, type: ParameterType.INT,
}, },
}, },
// prettier-ignore
citations: '__CITATIONS__',
}; };
type Info = typeof info; type Info = typeof info;

View File

@ -173,6 +173,8 @@ const info = <const>{
type: ParameterType.BOOL, type: ParameterType.BOOL,
}, },
}, },
// prettier-ignore
citations: '__CITATIONS__',
}; };
type Info = typeof info; type Info = typeof info;

View File

@ -27,6 +27,8 @@ const info = <const>{
default: undefined, default: undefined,
}, },
}, },
// prettier-ignore
citations: '__CITATIONS__',
}; };
type Info = typeof info; type Info = typeof info;

View File

@ -113,6 +113,8 @@ const info = <const>{
type: ParameterType.INT, type: ParameterType.INT,
}, },
}, },
// prettier-ignore
citations: '__CITATIONS__',
}; };
type Info = typeof info; type Info = typeof info;

View File

@ -78,6 +78,8 @@ const info = <const>{
type: ParameterType.INT, type: ParameterType.INT,
}, },
}, },
// prettier-ignore
citations: '__CITATIONS__',
}; };
type Info = typeof info; type Info = typeof info;

View File

@ -90,6 +90,8 @@ const info = <const>{
type: ParameterType.STRING, type: ParameterType.STRING,
}, },
}, },
// prettier-ignore
citations: '__CITATIONS__',
}; };
type Info = typeof info; type Info = typeof info;

View File

@ -90,6 +90,8 @@ const info = <const>{
type: ParameterType.BOOL, type: ParameterType.BOOL,
}, },
}, },
// prettier-ignore
citations: '__CITATIONS__',
}; };
type Info = typeof info; type Info = typeof info;

View File

@ -95,6 +95,8 @@ const info = <const>{
type: ParameterType.BOOL, type: ParameterType.BOOL,
}, },
}, },
// prettier-ignore
citations: '__CITATIONS__',
}; };
type Info = typeof info; type Info = typeof info;

View File

@ -96,6 +96,8 @@ const info = <const>{
type: ParameterType.BOOL, type: ParameterType.BOOL,
}, },
}, },
// prettier-ignore
citations: '__CITATIONS__',
}; };
type Info = typeof info; type Info = typeof info;

View File

@ -75,6 +75,8 @@ const info = <const>{
array: true, array: true,
}, },
}, },
// prettier-ignore
citations: '__CITATIONS__',
}; };
type Info = typeof info; type Info = typeof info;

View File

@ -48,6 +48,8 @@ const info = <const>{
type: ParameterType.INT, type: ParameterType.INT,
}, },
}, },
// prettier-ignore
citations: '__CITATIONS__',
}; };
type Info = typeof info; type Info = typeof info;

View File

@ -167,6 +167,8 @@ const info = <const>{
type: ParameterType.INT, type: ParameterType.INT,
}, },
}, },
// prettier-ignore
citations: '__CITATIONS__',
}; };
type Info = typeof info; type Info = typeof info;

View File

@ -46,6 +46,8 @@ const info = <const>{
description: "Time in milliseconds until the user entered fullscreen mode.", description: "Time in milliseconds until the user entered fullscreen mode.",
}, },
}, },
// prettier-ignore
citations: '__CITATIONS__',
}; };
type Info = typeof info; type Info = typeof info;

View File

@ -75,6 +75,8 @@ const info = <const>{
type: ParameterType.STRING, type: ParameterType.STRING,
}, },
}, },
// prettier-ignore
citations: '__CITATIONS__',
}; };
type Info = typeof info; type Info = typeof info;

View File

@ -85,6 +85,8 @@ const info = <const>{
type: ParameterType.HTML_STRING, type: ParameterType.HTML_STRING,
}, },
}, },
// prettier-ignore
citations: '__CITATIONS__',
}; };
type Info = typeof info; type Info = typeof info;

View File

@ -80,6 +80,8 @@ const info = <const>{
type: ParameterType.STRING, type: ParameterType.STRING,
}, },
}, },
// prettier-ignore
citations: '__CITATIONS__',
}; };
type Info = typeof info; type Info = typeof info;

View File

@ -92,6 +92,8 @@ const info = <const>{
type: ParameterType.INT, type: ParameterType.INT,
}, },
}, },
// prettier-ignore
citations: '__CITATIONS__',
}; };
type Info = typeof info; type Info = typeof info;

View File

@ -80,6 +80,8 @@ const info = <const>{
type: ParameterType.STRING, type: ParameterType.STRING,
}, },
}, },
// prettier-ignore
citations: '__CITATIONS__',
}; };
type Info = typeof info; type Info = typeof info;

View File

@ -111,6 +111,8 @@ const info = <const>{
type: ParameterType.INT, type: ParameterType.INT,
}, },
}, },
// prettier-ignore
citations: '__CITATIONS__',
}; };
type Info = typeof info; type Info = typeof info;

View File

@ -111,6 +111,8 @@ const info = <const>{
type: ParameterType.INT, type: ParameterType.INT,
}, },
}, },
// prettier-ignore
citations: '__CITATIONS__',
}; };
type Info = typeof info; type Info = typeof info;

View File

@ -124,6 +124,8 @@ const info = <const>{
type: ParameterType.INT, type: ParameterType.INT,
}, },
}, },
// prettier-ignore
citations: '__CITATIONS__',
}; };
type Info = typeof info; type Info = typeof info;

View File

@ -88,6 +88,8 @@ const info = <const>{
type: ParameterType.INT, type: ParameterType.INT,
}, },
}, },
// prettier-ignore
citations: '__CITATIONS__',
}; };
type Info = typeof info; type Info = typeof info;

View File

@ -128,6 +128,8 @@ const info = <const>{
type: ParameterType.INT, type: ParameterType.INT,
}, },
}, },
// prettier-ignore
citations: '__CITATIONS__',
}; };
type Info = typeof info; type Info = typeof info;

View File

@ -48,6 +48,8 @@ const info = <const>{
type: ParameterType.STRING, type: ParameterType.STRING,
}, },
}, },
// prettier-ignore
citations: '__CITATIONS__',
}; };
type Info = typeof info; type Info = typeof info;

View File

@ -23,6 +23,8 @@ const info = <const>{
type: ParameterType.STRING, type: ParameterType.STRING,
}, },
}, },
// prettier-ignore
citations: '__CITATIONS__',
}; };
type Info = typeof info; type Info = typeof info;

View File

@ -92,6 +92,8 @@ const info = <const>{
type: ParameterType.INT, type: ParameterType.INT,
}, },
}, },
// prettier-ignore
citations: '__CITATIONS__',
}; };
type Info = typeof info; type Info = typeof info;

View File

@ -75,6 +75,8 @@ const info = <const>{
}, },
}, },
}, },
// prettier-ignore
citations: '__CITATIONS__',
}; };
type Info = typeof info; type Info = typeof info;

View File

@ -38,6 +38,8 @@ const info = <const>{
type: ParameterType.INT, type: ParameterType.INT,
}, },
}, },
// prettier-ignore
citations: '__CITATIONS__',
}; };
type Info = typeof info; type Info = typeof info;

View File

@ -134,6 +134,8 @@ const info = <const>{
array: true, array: true,
}, },
}, },
// prettier-ignore
citations: '__CITATIONS__',
}; };
type Info = typeof info; type Info = typeof info;

View File

@ -52,6 +52,8 @@ const info = <const>{
type: ParameterType.INT, type: ParameterType.INT,
}, },
}, },
// prettier-ignore
citations: '__CITATIONS__',
}; };
type Info = typeof info; type Info = typeof info;

View File

@ -50,6 +50,8 @@ const info = <const>{
type: ParameterType.FLOAT, type: ParameterType.FLOAT,
}, },
}, },
// prettier-ignore
citations: '__CITATIONS__',
}; };
type Info = typeof info; type Info = typeof info;

View File

@ -76,6 +76,8 @@ const info = <const>{
type: ParameterType.STRING, type: ParameterType.STRING,
}, },
}, },
// prettier-ignore
citations: '__CITATIONS__',
}; };
type Info = typeof info; type Info = typeof info;

View File

@ -78,6 +78,8 @@ const info = <const>{
type: ParameterType.STRING, type: ParameterType.STRING,
}, },
}, },
// prettier-ignore
citations: '__CITATIONS__',
}; };
type Info = typeof info; type Info = typeof info;

View File

@ -88,6 +88,8 @@ const info = <const>{
type: ParameterType.BOOL, type: ParameterType.BOOL,
}, },
}, },
// prettier-ignore
citations: '__CITATIONS__',
}; };
type Info = typeof info; type Info = typeof info;

View File

@ -98,6 +98,8 @@ const info = <const>{
type: ParameterType.BOOL, type: ParameterType.BOOL,
}, },
}, },
// prettier-ignore
citations: '__CITATIONS__',
}; };
type Info = typeof info; type Info = typeof info;

View File

@ -255,6 +255,8 @@ const info = <const>{
}, },
}, },
}, },
// prettier-ignore
citations: '__CITATIONS__',
}; };
type Info = typeof info; type Info = typeof info;

View File

@ -47,6 +47,8 @@ const info = <const>{
type: ParameterType.INT, type: ParameterType.INT,
}, },
}, },
// prettier-ignore
citations: '__CITATIONS__',
}; };
type Info = typeof info; type Info = typeof info;

View File

@ -75,6 +75,8 @@ const info = <const>{
array: true, array: true,
}, },
}, },
// prettier-ignore
citations: '__CITATIONS__',
}; };
type Info = typeof info; type Info = typeof info;

View File

@ -92,6 +92,8 @@ const info = <const>{
array: true, array: true,
}, },
}, },
// prettier-ignore
citations: '__CITATIONS__',
}; };
type Info = typeof info; type Info = typeof info;

View File

@ -97,6 +97,8 @@ const info = <const>{
array: true, array: true,
}, },
}, },
// prettier-ignore
citations: '__CITATIONS__',
}; };
type Info = typeof info; type Info = typeof info;

View File

@ -95,6 +95,8 @@ const info = <const>{
array: true, array: true,
}, },
}, },
// prettier-ignore
citations: '__CITATIONS__',
}; };
type Info = typeof info; type Info = typeof info;

View File

@ -53,6 +53,8 @@ const info = <const>{
type: ParameterType.INT, type: ParameterType.INT,
}, },
}, },
// prettier-ignore
citations: '__CITATIONS__',
}; };
type Info = typeof info; type Info = typeof info;

View File

@ -162,6 +162,8 @@ const info = <const>{
array: true, array: true,
}, },
}, },
// prettier-ignore
citations: '__CITATIONS__',
}; };
type Info = typeof info; type Info = typeof info;

View File

@ -109,6 +109,8 @@ const info = <const>{
array: true, array: true,
}, },
}, },
// prettier-ignore
citations: '__CITATIONS__',
}; };
type Info = typeof info; type Info = typeof info;

View File

@ -164,6 +164,8 @@ const info = <const>{
type: ParameterType.FLOAT, type: ParameterType.FLOAT,
}, },
}, },
// prettier-ignore
citations: '__CITATIONS__',
}; };
type Info = typeof info; type Info = typeof info;

View File

@ -170,6 +170,8 @@ const info = <const>{
type: ParameterType.FLOAT, type: ParameterType.FLOAT,
}, },
}, },
// prettier-ignore
citations: '__CITATIONS__',
}; };
type Info = typeof info; type Info = typeof info;

View File

@ -148,6 +148,8 @@ const info = <const>{
array: true, array: true,
}, },
}, },
// prettier-ignore
citations: '__CITATIONS__',
}; };
type Info = typeof info; type Info = typeof info;

View File

@ -62,6 +62,8 @@ const info = <const>{
data: { data: {
// no data collected // no data collected
}, },
// prettier-ignore
citations: '__CITATIONS__',
}; };
type Info = typeof info; type Info = typeof info;

View File

@ -30,6 +30,8 @@ const info = <const>{
type: ParameterType.INT, type: ParameterType.INT,
}, },
}, },
// prettier-ignore
citations: '__CITATIONS__',
}; };
type Info = typeof info; type Info = typeof info;

View File

@ -103,6 +103,8 @@ const info = <const>{
array: true, array: true,
}, },
}, },
// prettier-ignore
citations: '__CITATIONS__',
}; };
type Info = typeof info; type Info = typeof info;