mirror of
https://github.com/jspsych/jsPsych.git
synced 2025-05-10 11:10:54 +00:00
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:
commit
2ddc120bed
62
.changeset/violet-tools-appear.md
Normal file
62
.changeset/violet-tools-appear.md
Normal 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
1
.gitignore
vendored
@ -11,3 +11,4 @@ coverage/
|
||||
dist.zip
|
||||
packages/jspsych/README.md
|
||||
.turbo
|
||||
.env
|
||||
|
@ -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:
|
||||
|
||||
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:
|
||||
|
||||
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.
|
||||
|
||||
#### 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"`).
|
@ -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.
|
||||
|
||||
* **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!
|
||||
|
||||
* **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!
|
||||
|
@ -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.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
|
||||
|
||||
|
8385
package-lock.json
generated
8385
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -27,8 +27,8 @@
|
||||
"devDependencies": {
|
||||
"@changesets/changelog-github": "^0.4.7",
|
||||
"@changesets/cli": "^2.25.2",
|
||||
"@jspsych/config": "^1.3.2",
|
||||
"husky": "^8.0.2",
|
||||
"@jspsych/config": "^3.0.0",
|
||||
"husky": "^8.0.3",
|
||||
"import-sort-style-module": "^6.0.0",
|
||||
"lint-staged": "^13.0.3",
|
||||
"prettier": "^2.7.1",
|
||||
|
94
packages/config/generateCitations.js
Normal file
94
packages/config/generateCitations.js
Normal 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;
|
||||
}
|
@ -35,12 +35,18 @@
|
||||
},
|
||||
"homepage": "https://www.jspsych.org/latest/developers/configuration",
|
||||
"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-node-resolve": "15.2.3",
|
||||
"@rollup/plugin-replace": "^6.0.1",
|
||||
"@sucrase/jest-plugin": "3.0.0",
|
||||
"@types/gulp": "4.0.17",
|
||||
"@types/jest": "29.5.8",
|
||||
"alias-hq": "6.2.4",
|
||||
"app-root-path": "^3.1.0",
|
||||
"canvas": "^2.11.2",
|
||||
"esbuild": "0.23.1",
|
||||
"gulp": "5.0.0",
|
||||
@ -55,9 +61,11 @@
|
||||
"rollup": "4.21.2",
|
||||
"rollup-plugin-dts": "6.1.1",
|
||||
"rollup-plugin-esbuild": "6.1.1",
|
||||
"rollup-plugin-modify": "^3.0.0",
|
||||
"rollup-plugin-node-externals": "7.1.3",
|
||||
"sucrase": "3.34.0",
|
||||
"tslib": "2.6.2",
|
||||
"typescript": "^5.2.2"
|
||||
"typescript": "^5.2.2",
|
||||
"yaml": "^2.5.1"
|
||||
}
|
||||
}
|
||||
|
@ -6,9 +6,12 @@ import resolve from "@rollup/plugin-node-resolve";
|
||||
import { defineConfig } from "rollup";
|
||||
import dts from "rollup-plugin-dts";
|
||||
import esbuild from "rollup-plugin-esbuild";
|
||||
import modify from "rollup-plugin-modify";
|
||||
import externals from "rollup-plugin-node-externals";
|
||||
import ts from "typescript";
|
||||
|
||||
import generateCitations from "./generateCitations.js";
|
||||
|
||||
const getTsCompilerOptions = () => {
|
||||
const cwd = process.cwd();
|
||||
return ts.parseJsonConfigFileContent(
|
||||
@ -38,6 +41,8 @@ const makeConfig = ({
|
||||
...outputOptions,
|
||||
};
|
||||
|
||||
const citationData = generateCitations();
|
||||
|
||||
/** @type{import("rollup-plugin-esbuild").Options} */
|
||||
const esBuildPluginOptions = {
|
||||
loaders: { ".json": "json" },
|
||||
@ -71,6 +76,11 @@ const makeConfig = ({
|
||||
input,
|
||||
plugins: [
|
||||
externals(),
|
||||
modify({
|
||||
// prettier-ignore
|
||||
find: /'__CITATIONS__'/g,
|
||||
replace: JSON.stringify(citationData, null, 2),
|
||||
}),
|
||||
esbuild({ ...esBuildPluginOptions, target: "node18" }),
|
||||
commonjs(commonjsPluginOptions),
|
||||
],
|
||||
@ -96,6 +106,11 @@ const makeConfig = ({
|
||||
input,
|
||||
plugins: [
|
||||
externals({ deps: false }),
|
||||
modify({
|
||||
// prettier-ignore
|
||||
find: /'__CITATIONS__'/g,
|
||||
replace: JSON.stringify(citationData, null, 2),
|
||||
}),
|
||||
resolve({ preferBuiltins: false }),
|
||||
esbuild({ ...esBuildPluginOptions, target: "esnext" }),
|
||||
commonjs(commonjsPluginOptions),
|
||||
@ -115,6 +130,11 @@ const makeConfig = ({
|
||||
input,
|
||||
plugins: [
|
||||
externals({ deps: false }),
|
||||
modify({
|
||||
// prettier-ignore
|
||||
find: /'__CITATIONS__'/g,
|
||||
replace: JSON.stringify(citationData, null, 2),
|
||||
}),
|
||||
resolve({ preferBuiltins: false }),
|
||||
esbuild({ ...esBuildPluginOptions, target: "es2015", minify: true }),
|
||||
commonjs(commonjsPluginOptions),
|
||||
@ -164,8 +184,9 @@ export const makeCoreRollupConfig = () =>
|
||||
/**
|
||||
* Returns the rollup configuration for Node.js-only packages
|
||||
*/
|
||||
export const makeNodeRollupConfig = () =>
|
||||
makeConfig({
|
||||
export const makeNodeRollupConfig = () => {
|
||||
return makeConfig({
|
||||
globalOptions: { external: ["jspsych"] },
|
||||
isNodeOnlyBuild: true,
|
||||
});
|
||||
};
|
||||
|
@ -95,6 +95,8 @@ class MouseTrackingExtension implements JsPsychExtension {
|
||||
},
|
||||
},
|
||||
},
|
||||
// prettier-ignore
|
||||
citations: '__CITATIONS__',
|
||||
};
|
||||
|
||||
constructor(private jsPsych: JsPsych) {}
|
||||
|
@ -16,6 +16,8 @@ class RecordVideoExtension implements JsPsychExtension {
|
||||
type: ParameterType.STRING,
|
||||
},
|
||||
},
|
||||
// prettier-ignore
|
||||
citations: '__CITATIONS__',
|
||||
};
|
||||
|
||||
constructor(private jsPsych: JsPsych) {
|
||||
|
@ -91,6 +91,8 @@ class WebGazerExtension implements JsPsychExtension {
|
||||
},
|
||||
},
|
||||
},
|
||||
// prettier-ignore
|
||||
citations: '__CITATIONS__',
|
||||
};
|
||||
|
||||
constructor(private jsPsych: JsPsych) {}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { Class } from "type-fest";
|
||||
|
||||
import { TestExtension } from "../tests/extensions/test-extension";
|
||||
import { TestExtension } from "../tests/extensions/TestExtension";
|
||||
import { ExtensionManager, ExtensionManagerDependencies } from "./ExtensionManager";
|
||||
import { JsPsych } from "./JsPsych";
|
||||
import { JsPsychExtension } from "./modules/extensions";
|
||||
|
@ -1,9 +1,13 @@
|
||||
import autoBind from "auto-bind";
|
||||
// To work with citations
|
||||
import { Class } from "type-fest";
|
||||
|
||||
import { version } from "../package.json";
|
||||
import { ExtensionManager, ExtensionManagerDependencies } from "./ExtensionManager";
|
||||
import { JsPsychData, JsPsychDataDependencies } from "./modules/data";
|
||||
import { JsPsychExtension } from "./modules/extensions";
|
||||
import { PluginAPI, createJointPluginAPIObject } from "./modules/plugin-api";
|
||||
import { JsPsychPlugin } from "./modules/plugins";
|
||||
import * as randomization from "./modules/randomization";
|
||||
import * as turk from "./modules/turk";
|
||||
import * as utils from "./modules/utils";
|
||||
@ -257,6 +261,48 @@ export class JsPsych {
|
||||
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() {
|
||||
return this.extensionManager?.extensions ?? {};
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ export interface JsPsychExtensionInfo {
|
||||
name: string;
|
||||
version?: string;
|
||||
data?: ParameterInfos;
|
||||
citations?: Record<string, string> | string;
|
||||
}
|
||||
|
||||
export interface JsPsychExtension {
|
||||
|
@ -141,6 +141,7 @@ export interface PluginInfo {
|
||||
version?: string;
|
||||
parameters: ParameterInfos;
|
||||
data?: ParameterInfos;
|
||||
citations?: Record<string, string> | string;
|
||||
}
|
||||
|
||||
export interface JsPsychPlugin<I extends PluginInfo> {
|
||||
|
@ -10,6 +10,10 @@ export const testPluginInfo = <const>{
|
||||
version: "0.0.1",
|
||||
parameters: {},
|
||||
data: {},
|
||||
citations: {
|
||||
apa: "Test plugin APA citation",
|
||||
bibtex: "Test plugin BibTeX citation",
|
||||
},
|
||||
};
|
||||
|
||||
class TestPlugin implements JsPsychPlugin<typeof testPluginInfo> {
|
||||
|
94
packages/jspsych/tests/citations/citations.test.ts
Normal file
94
packages/jspsych/tests/citations/citations.test.ts
Normal 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);
|
||||
});
|
||||
});
|
||||
}
|
@ -5,6 +5,10 @@ export class TestExtension implements JsPsychExtension {
|
||||
name: "test",
|
||||
version: "0.0.1",
|
||||
data: {},
|
||||
citations: {
|
||||
apa: "Test extension APA citation",
|
||||
bibtex: "Test extension BibTeX citation",
|
||||
},
|
||||
};
|
||||
|
||||
constructor(private jsPsych: JsPsych) {}
|
@ -2,7 +2,7 @@ import htmlKeyboardResponse from "@jspsych/plugin-html-keyboard-response";
|
||||
import { pressKey, startTimeline } from "@jspsych/test-utils";
|
||||
|
||||
import { JsPsych, initJsPsych } from "../../src";
|
||||
import { TestExtension } from "./test-extension";
|
||||
import { TestExtension } from "./TestExtension";
|
||||
|
||||
jest.useFakeTimers();
|
||||
|
||||
|
@ -96,6 +96,8 @@ const info = <const>{
|
||||
},
|
||||
},
|
||||
},
|
||||
// prettier-ignore
|
||||
citations: '__CITATIONS__',
|
||||
};
|
||||
|
||||
type Info = typeof info;
|
||||
|
@ -114,6 +114,8 @@ const info = <const>{
|
||||
type: ParameterType.INT,
|
||||
},
|
||||
},
|
||||
// prettier-ignore
|
||||
citations: '__CITATIONS__',
|
||||
};
|
||||
|
||||
type Info = typeof info;
|
||||
|
@ -82,6 +82,8 @@ const info = <const>{
|
||||
type: ParameterType.STRING,
|
||||
},
|
||||
},
|
||||
// prettier-ignore
|
||||
citations: '__CITATIONS__',
|
||||
};
|
||||
|
||||
type Info = typeof info;
|
||||
|
@ -117,6 +117,8 @@ const info = <const>{
|
||||
type: ParameterType.INT,
|
||||
},
|
||||
},
|
||||
// prettier-ignore
|
||||
citations: '__CITATIONS__',
|
||||
};
|
||||
|
||||
type Info = typeof info;
|
||||
|
@ -173,6 +173,8 @@ const info = <const>{
|
||||
type: ParameterType.BOOL,
|
||||
},
|
||||
},
|
||||
// prettier-ignore
|
||||
citations: '__CITATIONS__',
|
||||
};
|
||||
|
||||
type Info = typeof info;
|
||||
|
@ -27,6 +27,8 @@ const info = <const>{
|
||||
default: undefined,
|
||||
},
|
||||
},
|
||||
// prettier-ignore
|
||||
citations: '__CITATIONS__',
|
||||
};
|
||||
|
||||
type Info = typeof info;
|
||||
|
@ -113,6 +113,8 @@ const info = <const>{
|
||||
type: ParameterType.INT,
|
||||
},
|
||||
},
|
||||
// prettier-ignore
|
||||
citations: '__CITATIONS__',
|
||||
};
|
||||
|
||||
type Info = typeof info;
|
||||
|
@ -78,6 +78,8 @@ const info = <const>{
|
||||
type: ParameterType.INT,
|
||||
},
|
||||
},
|
||||
// prettier-ignore
|
||||
citations: '__CITATIONS__',
|
||||
};
|
||||
|
||||
type Info = typeof info;
|
||||
|
@ -90,6 +90,8 @@ const info = <const>{
|
||||
type: ParameterType.STRING,
|
||||
},
|
||||
},
|
||||
// prettier-ignore
|
||||
citations: '__CITATIONS__',
|
||||
};
|
||||
|
||||
type Info = typeof info;
|
||||
|
@ -90,6 +90,8 @@ const info = <const>{
|
||||
type: ParameterType.BOOL,
|
||||
},
|
||||
},
|
||||
// prettier-ignore
|
||||
citations: '__CITATIONS__',
|
||||
};
|
||||
|
||||
type Info = typeof info;
|
||||
|
@ -95,6 +95,8 @@ const info = <const>{
|
||||
type: ParameterType.BOOL,
|
||||
},
|
||||
},
|
||||
// prettier-ignore
|
||||
citations: '__CITATIONS__',
|
||||
};
|
||||
|
||||
type Info = typeof info;
|
||||
|
@ -96,6 +96,8 @@ const info = <const>{
|
||||
type: ParameterType.BOOL,
|
||||
},
|
||||
},
|
||||
// prettier-ignore
|
||||
citations: '__CITATIONS__',
|
||||
};
|
||||
|
||||
type Info = typeof info;
|
||||
|
@ -75,6 +75,8 @@ const info = <const>{
|
||||
array: true,
|
||||
},
|
||||
},
|
||||
// prettier-ignore
|
||||
citations: '__CITATIONS__',
|
||||
};
|
||||
|
||||
type Info = typeof info;
|
||||
|
@ -48,6 +48,8 @@ const info = <const>{
|
||||
type: ParameterType.INT,
|
||||
},
|
||||
},
|
||||
// prettier-ignore
|
||||
citations: '__CITATIONS__',
|
||||
};
|
||||
|
||||
type Info = typeof info;
|
||||
|
@ -167,6 +167,8 @@ const info = <const>{
|
||||
type: ParameterType.INT,
|
||||
},
|
||||
},
|
||||
// prettier-ignore
|
||||
citations: '__CITATIONS__',
|
||||
};
|
||||
|
||||
type Info = typeof info;
|
||||
|
@ -46,6 +46,8 @@ const info = <const>{
|
||||
description: "Time in milliseconds until the user entered fullscreen mode.",
|
||||
},
|
||||
},
|
||||
// prettier-ignore
|
||||
citations: '__CITATIONS__',
|
||||
};
|
||||
|
||||
type Info = typeof info;
|
||||
|
@ -75,6 +75,8 @@ const info = <const>{
|
||||
type: ParameterType.STRING,
|
||||
},
|
||||
},
|
||||
// prettier-ignore
|
||||
citations: '__CITATIONS__',
|
||||
};
|
||||
|
||||
type Info = typeof info;
|
||||
|
@ -85,6 +85,8 @@ const info = <const>{
|
||||
type: ParameterType.HTML_STRING,
|
||||
},
|
||||
},
|
||||
// prettier-ignore
|
||||
citations: '__CITATIONS__',
|
||||
};
|
||||
|
||||
type Info = typeof info;
|
||||
|
@ -80,6 +80,8 @@ const info = <const>{
|
||||
type: ParameterType.STRING,
|
||||
},
|
||||
},
|
||||
// prettier-ignore
|
||||
citations: '__CITATIONS__',
|
||||
};
|
||||
|
||||
type Info = typeof info;
|
||||
|
@ -92,6 +92,8 @@ const info = <const>{
|
||||
type: ParameterType.INT,
|
||||
},
|
||||
},
|
||||
// prettier-ignore
|
||||
citations: '__CITATIONS__',
|
||||
};
|
||||
|
||||
type Info = typeof info;
|
||||
|
@ -80,6 +80,8 @@ const info = <const>{
|
||||
type: ParameterType.STRING,
|
||||
},
|
||||
},
|
||||
// prettier-ignore
|
||||
citations: '__CITATIONS__',
|
||||
};
|
||||
|
||||
type Info = typeof info;
|
||||
|
@ -111,6 +111,8 @@ const info = <const>{
|
||||
type: ParameterType.INT,
|
||||
},
|
||||
},
|
||||
// prettier-ignore
|
||||
citations: '__CITATIONS__',
|
||||
};
|
||||
|
||||
type Info = typeof info;
|
||||
|
@ -111,6 +111,8 @@ const info = <const>{
|
||||
type: ParameterType.INT,
|
||||
},
|
||||
},
|
||||
// prettier-ignore
|
||||
citations: '__CITATIONS__',
|
||||
};
|
||||
|
||||
type Info = typeof info;
|
||||
|
@ -124,6 +124,8 @@ const info = <const>{
|
||||
type: ParameterType.INT,
|
||||
},
|
||||
},
|
||||
// prettier-ignore
|
||||
citations: '__CITATIONS__',
|
||||
};
|
||||
|
||||
type Info = typeof info;
|
||||
|
@ -88,6 +88,8 @@ const info = <const>{
|
||||
type: ParameterType.INT,
|
||||
},
|
||||
},
|
||||
// prettier-ignore
|
||||
citations: '__CITATIONS__',
|
||||
};
|
||||
|
||||
type Info = typeof info;
|
||||
|
@ -128,6 +128,8 @@ const info = <const>{
|
||||
type: ParameterType.INT,
|
||||
},
|
||||
},
|
||||
// prettier-ignore
|
||||
citations: '__CITATIONS__',
|
||||
};
|
||||
|
||||
type Info = typeof info;
|
||||
|
@ -48,6 +48,8 @@ const info = <const>{
|
||||
type: ParameterType.STRING,
|
||||
},
|
||||
},
|
||||
// prettier-ignore
|
||||
citations: '__CITATIONS__',
|
||||
};
|
||||
|
||||
type Info = typeof info;
|
||||
|
@ -23,6 +23,8 @@ const info = <const>{
|
||||
type: ParameterType.STRING,
|
||||
},
|
||||
},
|
||||
// prettier-ignore
|
||||
citations: '__CITATIONS__',
|
||||
};
|
||||
|
||||
type Info = typeof info;
|
||||
|
@ -92,6 +92,8 @@ const info = <const>{
|
||||
type: ParameterType.INT,
|
||||
},
|
||||
},
|
||||
// prettier-ignore
|
||||
citations: '__CITATIONS__',
|
||||
};
|
||||
|
||||
type Info = typeof info;
|
||||
|
@ -75,6 +75,8 @@ const info = <const>{
|
||||
},
|
||||
},
|
||||
},
|
||||
// prettier-ignore
|
||||
citations: '__CITATIONS__',
|
||||
};
|
||||
|
||||
type Info = typeof info;
|
||||
|
@ -38,6 +38,8 @@ const info = <const>{
|
||||
type: ParameterType.INT,
|
||||
},
|
||||
},
|
||||
// prettier-ignore
|
||||
citations: '__CITATIONS__',
|
||||
};
|
||||
|
||||
type Info = typeof info;
|
||||
|
@ -134,6 +134,8 @@ const info = <const>{
|
||||
array: true,
|
||||
},
|
||||
},
|
||||
// prettier-ignore
|
||||
citations: '__CITATIONS__',
|
||||
};
|
||||
|
||||
type Info = typeof info;
|
||||
|
@ -52,6 +52,8 @@ const info = <const>{
|
||||
type: ParameterType.INT,
|
||||
},
|
||||
},
|
||||
// prettier-ignore
|
||||
citations: '__CITATIONS__',
|
||||
};
|
||||
|
||||
type Info = typeof info;
|
||||
|
@ -50,6 +50,8 @@ const info = <const>{
|
||||
type: ParameterType.FLOAT,
|
||||
},
|
||||
},
|
||||
// prettier-ignore
|
||||
citations: '__CITATIONS__',
|
||||
};
|
||||
|
||||
type Info = typeof info;
|
||||
|
@ -76,6 +76,8 @@ const info = <const>{
|
||||
type: ParameterType.STRING,
|
||||
},
|
||||
},
|
||||
// prettier-ignore
|
||||
citations: '__CITATIONS__',
|
||||
};
|
||||
|
||||
type Info = typeof info;
|
||||
|
@ -78,6 +78,8 @@ const info = <const>{
|
||||
type: ParameterType.STRING,
|
||||
},
|
||||
},
|
||||
// prettier-ignore
|
||||
citations: '__CITATIONS__',
|
||||
};
|
||||
|
||||
type Info = typeof info;
|
||||
|
@ -88,6 +88,8 @@ const info = <const>{
|
||||
type: ParameterType.BOOL,
|
||||
},
|
||||
},
|
||||
// prettier-ignore
|
||||
citations: '__CITATIONS__',
|
||||
};
|
||||
|
||||
type Info = typeof info;
|
||||
|
@ -98,6 +98,8 @@ const info = <const>{
|
||||
type: ParameterType.BOOL,
|
||||
},
|
||||
},
|
||||
// prettier-ignore
|
||||
citations: '__CITATIONS__',
|
||||
};
|
||||
|
||||
type Info = typeof info;
|
||||
|
@ -255,6 +255,8 @@ const info = <const>{
|
||||
},
|
||||
},
|
||||
},
|
||||
// prettier-ignore
|
||||
citations: '__CITATIONS__',
|
||||
};
|
||||
|
||||
type Info = typeof info;
|
||||
|
@ -47,6 +47,8 @@ const info = <const>{
|
||||
type: ParameterType.INT,
|
||||
},
|
||||
},
|
||||
// prettier-ignore
|
||||
citations: '__CITATIONS__',
|
||||
};
|
||||
|
||||
type Info = typeof info;
|
||||
|
@ -75,6 +75,8 @@ const info = <const>{
|
||||
array: true,
|
||||
},
|
||||
},
|
||||
// prettier-ignore
|
||||
citations: '__CITATIONS__',
|
||||
};
|
||||
|
||||
type Info = typeof info;
|
||||
|
@ -92,6 +92,8 @@ const info = <const>{
|
||||
array: true,
|
||||
},
|
||||
},
|
||||
// prettier-ignore
|
||||
citations: '__CITATIONS__',
|
||||
};
|
||||
|
||||
type Info = typeof info;
|
||||
|
@ -97,6 +97,8 @@ const info = <const>{
|
||||
array: true,
|
||||
},
|
||||
},
|
||||
// prettier-ignore
|
||||
citations: '__CITATIONS__',
|
||||
};
|
||||
|
||||
type Info = typeof info;
|
||||
|
@ -95,6 +95,8 @@ const info = <const>{
|
||||
array: true,
|
||||
},
|
||||
},
|
||||
// prettier-ignore
|
||||
citations: '__CITATIONS__',
|
||||
};
|
||||
|
||||
type Info = typeof info;
|
||||
|
@ -53,6 +53,8 @@ const info = <const>{
|
||||
type: ParameterType.INT,
|
||||
},
|
||||
},
|
||||
// prettier-ignore
|
||||
citations: '__CITATIONS__',
|
||||
};
|
||||
|
||||
type Info = typeof info;
|
||||
|
@ -162,6 +162,8 @@ const info = <const>{
|
||||
array: true,
|
||||
},
|
||||
},
|
||||
// prettier-ignore
|
||||
citations: '__CITATIONS__',
|
||||
};
|
||||
|
||||
type Info = typeof info;
|
||||
|
@ -109,6 +109,8 @@ const info = <const>{
|
||||
array: true,
|
||||
},
|
||||
},
|
||||
// prettier-ignore
|
||||
citations: '__CITATIONS__',
|
||||
};
|
||||
|
||||
type Info = typeof info;
|
||||
|
@ -164,6 +164,8 @@ const info = <const>{
|
||||
type: ParameterType.FLOAT,
|
||||
},
|
||||
},
|
||||
// prettier-ignore
|
||||
citations: '__CITATIONS__',
|
||||
};
|
||||
|
||||
type Info = typeof info;
|
||||
|
@ -170,6 +170,8 @@ const info = <const>{
|
||||
type: ParameterType.FLOAT,
|
||||
},
|
||||
},
|
||||
// prettier-ignore
|
||||
citations: '__CITATIONS__',
|
||||
};
|
||||
|
||||
type Info = typeof info;
|
||||
|
@ -148,6 +148,8 @@ const info = <const>{
|
||||
array: true,
|
||||
},
|
||||
},
|
||||
// prettier-ignore
|
||||
citations: '__CITATIONS__',
|
||||
};
|
||||
|
||||
type Info = typeof info;
|
||||
|
@ -62,6 +62,8 @@ const info = <const>{
|
||||
data: {
|
||||
// no data collected
|
||||
},
|
||||
// prettier-ignore
|
||||
citations: '__CITATIONS__',
|
||||
};
|
||||
|
||||
type Info = typeof info;
|
||||
|
@ -30,6 +30,8 @@ const info = <const>{
|
||||
type: ParameterType.INT,
|
||||
},
|
||||
},
|
||||
// prettier-ignore
|
||||
citations: '__CITATIONS__',
|
||||
};
|
||||
|
||||
type Info = typeof info;
|
||||
|
@ -103,6 +103,8 @@ const info = <const>{
|
||||
array: true,
|
||||
},
|
||||
},
|
||||
// prettier-ignore
|
||||
citations: '__CITATIONS__',
|
||||
};
|
||||
|
||||
type Info = typeof info;
|
||||
|
Loading…
Reference in New Issue
Block a user