diff --git a/.gitignore b/.gitignore
index b9e6aaaf7c..e9a081035a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,3 +11,5 @@ coverage/
dist.zip
packages/jspsych/README.md
.turbo
+*.pyc
+docs/__generator__/cache
diff --git a/docs/__generator__/plugins.py b/docs/__generator__/plugins.py
new file mode 100644
index 0000000000..ab7c8bb151
--- /dev/null
+++ b/docs/__generator__/plugins.py
@@ -0,0 +1,159 @@
+from pathlib import Path
+
+from docs.__generator__.utils import (
+ convert_blockquote_admonitions,
+ generate_badge_svg,
+ get_package_info,
+ get_plugin_description,
+ get_value_by_path,
+ get_values_by_path,
+ jsdoc_to_inline_markdown,
+ jsdoc_to_markdown,
+ plugin_name_to_camel_case,
+)
+
+PARAMETER_TYPE_MAPPING = {
+ "KEYS": "array of strings",
+ "BOOL": "boolean",
+ "STRING": "string",
+ "INT": "numeric",
+ "FLOAT": "numeric",
+ "FUNCTION": "function",
+ "KEY": "string",
+ "KEYS": "array of strings",
+ # "SELECT": "",
+ "HTML_STRING": "HTML string",
+ "IMAGE": "image file",
+ "AUDIO": "audio file",
+ "VIDEO": "video file",
+ # "OBJECT": "",
+ # "COMPLEX": "",
+ # "TIMELINE": "",
+}
+
+
+def generate_plugin_parameters_section(plugin_dir: Path):
+ description = get_plugin_description(plugin_dir)
+
+ output = """
+## Parameters
+
+In addition to the [parameters available in all
+plugins](../overview/plugins.md#parameters-available-in-all-plugins), this plugin
+accepts the following parameters. Parameters with a default value of undefined must be
+specified. Other parameters can be left unspecified if the default value is acceptable.
+
+| Parameter | Type | Default Value | Description |
+| --------- | ---- | ------------- | ----------- |
+"""
+
+ for parameter in get_values_by_path(
+ description,
+ "$.children[?name = default].children[?name = info].type.declaration.children[?name = parameters].type.declaration.children[?kindString = Property]",
+ ):
+ parameter_name = parameter["name"]
+
+ parameter_type = get_value_by_path(
+ parameter, "$.type.declaration.children[?name = type].type.name"
+ )
+ if parameter_type in PARAMETER_TYPE_MAPPING:
+ parameter_type = PARAMETER_TYPE_MAPPING[parameter_type]
+
+ is_array = get_value_by_path(
+ parameter, "$.type.declaration.children[?name = array].type.value"
+ )
+ if is_array:
+ parameter_type = f"array of {parameter_type}s"
+
+ default_value_description = get_value_by_path(
+ parameter, "$.type.declaration.children[?name = default]"
+ )
+
+ # If `default_value` has a TSDoc summary, display it as the default value
+ default_value_summary = get_value_by_path(
+ default_value_description, "$.comment.summary"
+ ) or get_value_by_path(
+ default_value_description,
+ "$.type.declaration.signatures[0].comment.summary",
+ )
+ if default_value_summary:
+ default_value = jsdoc_to_inline_markdown(default_value_summary)
+ else:
+ default_value = get_value_by_path(
+ default_value_description, "$.defaultValue"
+ )
+
+ # Large arrays are not displayed by default, so assembling a custom string
+ # here
+ if is_array and default_value == "...":
+ default_array_values = get_values_by_path(
+ default_value_description, "$.type.target.elements[*].value"
+ )
+
+ if default_array_values:
+ separator = '", "'
+ default_value = f'["{separator.join(default_array_values)}"]'
+
+ is_required = default_value == "undefined"
+ required_marker = "*" if is_required else ""
+ if is_required:
+ default_value = ""
+
+ description = jsdoc_to_inline_markdown(
+ get_values_by_path(parameter, "$.comment.summary[*]")
+ )
+
+ output += f"{parameter_name}{required_marker} | {parameter_type} | {default_value} | {description} \n"
+
+ return output
+
+
+def generate_plugin_summary(plugin_dir: Path):
+ summary = get_value_by_path(
+ get_plugin_description(plugin_dir),
+ "$.children[?name = default].comment.summary",
+ )
+ return convert_blockquote_admonitions(jsdoc_to_markdown(summary))
+
+
+def generate_plugin_version_info(plugin_dir: Path):
+ info = get_package_info(plugin_dir)
+ return f"[{generate_badge_svg('Current version',info['version'])}](https://github.com/jspsych/jsPsych/blob/main/{plugin_dir}/CHANGELOG.md)"
+
+
+def generate_plugin_author_info(plugin_dir: Path):
+ author = get_value_by_path(
+ get_plugin_description(plugin_dir),
+ "$.children[?name = default].comment.blockTags[?tag = @author].content[0].text",
+ )
+ return generate_badge_svg("Author", author, "lightgray")
+
+
+def generate_plugin_installation_section(plugin_dir: Path):
+ info = get_package_info(plugin_dir)
+ plugin_dir_name = plugin_dir.name
+
+ return f"""
+## Install
+
+Using the CDN-hosted JavaScript file:
+
+```js
+
+```
+
+Using the JavaScript file downloaded from a GitHub release dist archive:
+
+```js
+
+```
+
+Using NPM:
+
+```
+npm install {info["name"]}
+```
+```js
+import {plugin_name_to_camel_case(plugin_dir_name)} from '{info["name"]}';
+```
+"""
diff --git a/docs/__generator__/utils.py b/docs/__generator__/utils.py
new file mode 100644
index 0000000000..f5728faa0f
--- /dev/null
+++ b/docs/__generator__/utils.py
@@ -0,0 +1,135 @@
+import json
+import subprocess
+from hashlib import md5
+from logging import getLogger
+from pathlib import Path
+from tempfile import NamedTemporaryFile
+from typing import Any, List
+
+import requests
+from diskcache import Cache
+from jsonpath_ng.ext import parse
+
+cache = Cache(Path(__file__).parent / "cache")
+logger = getLogger("mkdocs")
+
+
+def hash_file(path: Path):
+ with path.open() as file:
+ return md5(file.read().encode("utf8")).hexdigest()
+
+
+def get_plugin_description(plugin_dir: Path):
+ cache_key = (
+ "get_plugin_description",
+ plugin_dir,
+ hash_file(plugin_dir / "src/index.ts"),
+ )
+ if cache_key in cache:
+ return cache[cache_key]
+
+ logger.info(f"Collecting parameter infos for {plugin_dir}...")
+ with NamedTemporaryFile() as json_file:
+
+ typedoc_command = (
+ subprocess.list2cmdline(
+ [
+ "node_modules/.bin/typedoc",
+ "--tsconfig",
+ plugin_dir / "tsconfig.json",
+ "--json",
+ f"{json_file.name}",
+ "--sort",
+ "source-order",
+ plugin_dir / "src/index.ts",
+ ]
+ ),
+ )
+
+ subprocess.run(
+ typedoc_command,
+ shell=True,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ universal_newlines=True,
+ )
+
+ description = json.load(json_file)
+
+ cache[cache_key] = description
+ return description
+
+
+def get_values_by_path(data, json_path: str):
+ return [match.value for match in parse(json_path).find(data)]
+
+
+def get_value_by_path(data, json_path: str):
+ values = get_values_by_path(data, json_path)
+ return values[0] if len(values) > 0 else None
+
+
+def jsdoc_to_markdown(fragments: List[Any]):
+ output = ""
+
+ for fragment in fragments:
+ if fragment["kind"] in ["text", "code"]:
+ output += fragment["text"]
+
+ elif fragment["kind"] == "inline-tag":
+ if fragment["tag"] == "@link":
+ output += (
+ f'[{fragment["text"] or fragment["target"]}]({fragment["target"]})'
+ )
+
+ return output
+
+
+def jsdoc_to_inline_markdown(fragments: List[Any]):
+ return jsdoc_to_markdown(fragments).replace("\n\n", "
").replace("\n", " ")
+
+
+def convert_blockquote_admonitions(input: str):
+ """
+ Replace blockquote-based admonitions with MkDocs' admonition style
+ """
+ lines = input.split("\n")
+ is_blockquote = False
+ for index, line in enumerate(lines):
+ if line.startswith("> **"):
+ lines[index] = "!!! " + line[2:].replace("**", "")
+ is_blockquote = True
+
+ elif is_blockquote:
+ if line.startswith(">"):
+ lines[index] = " " + line[2:]
+ else:
+ is_blockquote = False
+
+ return "\n".join(lines)
+
+
+def plugin_name_to_camel_case(plugin_name: str):
+ words = plugin_name.split("-")
+ return words[1] + "".join([word.capitalize() for word in words[2:]])
+
+
+@cache.memoize(name="get_package_info", expire=60)
+def get_package_info(package_dir: Path):
+ with (package_dir / "package.json").open() as package_json_file:
+ package_json = json.load(package_json_file)
+ return {"name": package_json["name"], "version": package_json["version"]}
+
+
+@cache.memoize(name="generate_badge_svg")
+def generate_badge_svg(label: str, message: str, color="4cae4f"):
+
+ return requests.get(
+ f"https://img.shields.io/static/v1",
+ params={
+ "label": label,
+ "message": message,
+ "color": color,
+ "style": "flat-square",
+ },
+ ).text
diff --git a/docs/__init__.py b/docs/__init__.py
new file mode 100644
index 0000000000..daf5accc22
--- /dev/null
+++ b/docs/__init__.py
@@ -0,0 +1,29 @@
+from pathlib import Path
+
+from docs.__generator__.plugins import (
+ generate_plugin_author_info,
+ generate_plugin_installation_section,
+ generate_plugin_parameters_section,
+ generate_plugin_summary,
+ generate_plugin_version_info,
+)
+
+
+# https://mkdocs-macros-plugin.readthedocs.io/en/latest/macros/
+def define_env(env):
+ @env.macro
+ def plugin_parameters(plugin: str):
+ return generate_plugin_parameters_section(Path(f"packages/plugin-{plugin}"))
+
+ @env.macro
+ def plugin_description(plugin: str):
+ return generate_plugin_summary(Path(f"packages/plugin-{plugin}"))
+
+ @env.macro
+ def plugin_meta(plugin: str):
+ plugin_dir = Path(f"packages/plugin-{plugin}")
+ return f"{generate_plugin_version_info(plugin_dir)} {generate_plugin_author_info(plugin_dir)}\n"
+
+ @env.macro
+ def plugin_installation(plugin: str):
+ return generate_plugin_installation_section(Path(f"packages/plugin-{plugin}"))
diff --git a/docs/plugins/audio-button-response.md b/docs/plugins/audio-button-response.md
index a91d7e1195..0e1b6b5373 100644
--- a/docs/plugins/audio-button-response.md
+++ b/docs/plugins/audio-button-response.md
@@ -1,31 +1,8 @@
# audio-button-response
-Current version: 1.1.2. [See version history](https://github.com/jspsych/jsPsych/blob/main/packages/plugin-audio-button-response/CHANGELOG.md).
-
-This plugin plays audio files and records responses generated with a button click.
-
-If the browser supports it, audio files are played using the WebAudio API. This allows for reasonably precise timing of the playback. The timing of responses generated is measured against the WebAudio specific clock, improving the measurement of response times. If the browser does not support the WebAudio API, then the audio file is played with HTML5 audio.
-
-Audio files can be automatically preloaded by jsPsych using the [`preload` plugin](preload.md). However, if you are using timeline variables or another dynamic method to specify the audio stimulus, you will need to [manually preload](../overview/media-preloading.md#manual-preloading) the audio.
-
-The trial can end when the participant responds, when the audio file has finished playing, or if the participant has failed to respond within a fixed length of time. You can also prevent a button response from being made before the audio has finished playing.
-
-## Parameters
-
-In addition to the [parameters available in all plugins](../overview/plugins.md#parameters-available-in-all-plugins), this plugin accepts the following parameters. Parameters with a default value of *undefined* must be specified. Other parameters can be left unspecified if the default value is acceptable.
-
-| Parameter | Type | Default Value | Description |
-| ------------------------------ | ---------------- | ---------------------------------------- | ---------------------------------------- |
-| stimulus | audio file | *undefined* | Path to audio file to be played. |
-| choices | array of strings | *undefined* | Labels for the buttons. Each different string in the array will generate a different button. |
-| button_html | HTML string | `''` | A template of HTML for generating the button elements. You can override this to create customized buttons of various kinds. The string `%choice%` will be changed to the corresponding element of the `choices` array. You may also specify an array of strings, if you need different HTML to render for each button. If you do specify an array, the `choices` array and this array must have the same length. The HTML from position 0 in the `button_html` array will be used to create the button for element 0 in the `choices` array, and so on. |
-| prompt | string | null | This string can contain HTML markup. Any content here will be displayed below the stimulus. The intention is that it can be used to provide a reminder about the action the participant is supposed to take (e.g., which key to press). |
-| trial_duration | numeric | null | How long to wait for the participant to make a response before ending the trial in milliseconds. If the participant fails to make a response before this timer is reached, the participant's response will be recorded as null for the trial and the trial will end. If the value of this parameter is null, the trial will wait for a response indefinitely. |
-| margin_vertical | string | '0px' | Vertical margin of the button(s). |
-| margin_horizontal | string | '8px' | Horizontal margin of the button(s). |
-| response_ends_trial | boolean | true | If true, then the trial will end whenever the participant makes a response (assuming they make their response before the cutoff specified by the `trial_duration` parameter). If false, then the trial will continue until the value for `trial_duration` is reached. You can set this parameter to `false` to force the participant to listen to the stimulus for a fixed amount of time, even if they respond before the time is complete. |
-| trial_ends_after_audio | boolean | false | If true, then the trial will end as soon as the audio file finishes playing. |
-| response_allowed_while_playing | boolean | true | If true, then responses are allowed while the audio is playing. If false, then the audio must finish playing before the button choices are enabled and a response is accepted. Once the audio has played all the way through, the buttons are enabled and a response is allowed (including while the audio is being re-played via on-screen playback controls). |
+{{ plugin_meta('audio-button-response') }}
+{{ plugin_description('audio-button-response') }}
+{{ plugin_parameters('audio-button-response') }}
## Data Generated
@@ -42,28 +19,7 @@ In `data-only` simulation mode, the `response_allowed_while_playing` parameter d
This is because the audio file is not loaded in `data-only` mode and therefore the length is unknown.
This may change in a future version as we improve the simulation modes.
-## Install
-
-Using the CDN-hosted JavaScript file:
-
-```js
-
-```
-
-Using the JavaScript file downloaded from a GitHub release dist archive:
-
-```js
-
-```
-
-Using NPM:
-
-```
-npm install @jspsych/plugin-audio-button-response
-```
-```js
-import audioButtonResponse from '@jspsych/plugin-audio-button-response';
-```
+{{ plugin_installation('audio-button-response') }}
## Examples
diff --git a/docs/plugins/browser-check.md b/docs/plugins/browser-check.md
index 4d7c516fc4..1a307e2f63 100644
--- a/docs/plugins/browser-check.md
+++ b/docs/plugins/browser-check.md
@@ -1,49 +1,8 @@
# browser-check
-Current version: 1.0.2. [See version history](https://github.com/jspsych/jsPsych/blob/main/packages/plugin-browser-check/CHANGELOG.md).
-
-This plugin measures and records various features of the participant's browser and can end the experiment if defined inclusion criteria are not met.
-
-The plugin currently can record the following features:
-
-* The width and height of the browser window in pixels.
-* The type of browser used (e.g., Chrome, Firefox, Edge, etc.) and the version number of the browser.*
-* Whether the participant is using a mobile device.*
-* The operating system.*
-* Support for the WebAudio API.
-* Support for the Fullscreen API, e.g., through the [fullscreen plugin](../plugins/fullscreen.md).
-* The display refresh rate in frames per second.
-* Whether the device has a webcam and microphone. Note that this only reveals whether a webcam/microphone exists. The participant still needs to grant permission in order for the experiment to use these devices.
-
-!!! warning
- Features with an * are recorded by parsing the [user agent string](https://developer.mozilla.org/en-US/docs/Web/HTTP/Browser_detection_using_the_user_agent).
- This method is accurate most of the time, but is not guaranteed to be correct.
- The plugin uses the [detect-browser package](https://github.com/DamonOehlman/detect-browser) to perform user agent parsing.
- You can find a list of supported browsers and OSes in the [source file](https://github.com/DamonOehlman/detect-browser/blob/master/src/index.ts).
-
-The plugin begins by measuring the set of features requested.
-An inclusion function is evaluated to see if the paricipant passes the inclusion criteria.
-If they do, then the trial ends and the experiment continues.
-If they do not, then the experiment ends immediately.
-If a minimum width and/or minimum height is desired, the plugin will optionally display a message to participants whose browser windows are too small to give them an opportunity to make the window larger if possible.
-See the examples below for more guidance.
-
-## Parameters
-
-In addition to the [parameters available in all plugins](../overview/plugins.md#parameters-available-in-all-plugins), this plugin accepts the following parameters. Parameters with a default value of *undefined* must be specified. Other parameters can be left unspecified if the default value is acceptable.
-
-| Parameter | Type | Default Value | Description |
-| ------------------------------ | ---------------- | ------------- | ---------------------------------------- |
-| features | array of strings | `["width", "height", "webaudio", "browser", "browser_version", "mobile", "os", "fullscreen", "vsync_rate", "webcam", "microphone"]` | The list of browser features to record. The default value includes all of the available options. |
-| skip_features | array of strings | `[]` | Any features listed here will be skipped, even if they appear in `features`. Use this when you want to run most of the defaults.
-| vsync_frame_count | int | 60 | The number of frames to sample when measuring the display refresh rate (`"vsync_rate"`). Increasing the number will potenially improve the stability of the estimate at the cost of increasing the amount of time the plugin takes during this test. On most devices, 60 frames takes about 1 second to measure.
-| allow_window_resize | bool | true | Whether to allow the participant to resize the browser window if the window is smaller than `minimum_width` and/or `minimum_height`. If `false`, then the `minimum_width` and `minimum_height` parameters are ignored and you can validate the size in the `inclusion_function`.
-| minimum_height | int | 0 | If `allow_window_resize` is `true`, then this is the minimum height of the window (in pixels) that must be met before continuing.
-| minimum_width | int | 0 | If `allow_window_resize` is `true`, then this is the minimum width of the window (in pixels) that must be met before continuing.
-| window_resize_message | string | see description | The message that will be displayed during the interactive resize when `allow_window_resize` is `true` and the window is too small. If the message contains HTML elements with the special IDs `browser-check-min-width`, `browser-check-min-height`, `browser-check-actual-height`, and/or `browser-check-actual-width`, then the contents of those elements will be dynamically updated to reflect the `minimum_width`, `minimum_height` and measured width and height of the browser. The default message is: `
Your browser window is too small to complete this experiment. Please maximize the size of your browser window. If your browser window is already maximized, you will not be able to complete this experiment.
The minimum window width is px.
Your current window width is px.
The minimum window height is px.
Your current window height is px.
`.
-resize_fail_button_text | string | `"I cannot make the window any larger"` | During the interactive resize, a button with this text will be displayed below the `window_resize_message` for the participant to click if the window cannot meet the minimum size needed. When the button is clicked, the experiment will end and `exclusion_message` will be displayed.
-inclusion_function | function | `() => { return true; }` | A function that evaluates to `true` if the browser meets all of the inclusion criteria for the experiment, and `false` otherwise. The first argument to the function will be an object containing key value pairs with the measured features of the browser. The keys will be the same as those listed in `features`. See example below.
-exclusion_message | function | `() => { return
Your browser does not meet the requirements to participate in this experiment.
}` | A function that returns the message to display if `inclusion_function` evaluates to `false` or if the participant clicks on the resize fail button during the interactive resize. In order to allow customization of the message, the first argument to the function will be an object containing key value pairs with the measured features of the browser. The keys will be the same as those listed in `features`. See example below.
+{{ plugin_meta('browser-check') }}
+{{ plugin_description('browser-check') }}
+{{ plugin_parameters('browser-check') }}
## Data Generated
@@ -75,28 +34,7 @@ In `visual` mode, if `allow_window_resize` is true and the browser's width and h
As with all simulated plugins, you can override the default (actual) data with fake data using `simulation_options`. This allows you to test your exclusion criteria by simulating other configurations.
-## Install
-
-Using the CDN-hosted JavaScript file:
-
-```js
-
-```
-
-Using the JavaScript file downloaded from a GitHub release dist archive:
-
-```js
-
-```
-
-Using NPM:
-
-```
-npm install @jspsych/plugin-browser-check
-```
-```js
-import browserCheck from '@jspsych/plugin-browser-check';
-```
+{{ plugin_installation('browser-check') }}
## Examples
diff --git a/docs/plugins/html-keyboard-response.md b/docs/plugins/html-keyboard-response.md
index 9254f1715a..4806b28f23 100644
--- a/docs/plugins/html-keyboard-response.md
+++ b/docs/plugins/html-keyboard-response.md
@@ -1,22 +1,8 @@
# html-keyboard-response
-Current version: 1.1.2. [See version history](https://github.com/jspsych/jsPsych/blob/main/packages/plugin-html-keyboard-response/CHANGELOG.md).
-
-This plugin displays HTML content and records responses generated with the keyboard.The stimulus can be displayed until a response is given, or for a pre-determined amount of time. The trial can be ended automatically if the participant has failed to respond within a fixed length of time.
-
-
-## Parameters
-
-In addition to the [parameters available in all plugins](../overview/plugins.md#parameters-available-in-all-plugins), this plugin accepts the following parameters. Parameters with a default value of undefined must be specified. Other parameters can be left unspecified if the default value is acceptable.
-
-| Parameter | Type | Default Value | Description |
-| ------------------- | ---------------- | ------------------ | ---------------------------------------- |
-| stimulus | HTML string | *undefined* | The string to be displayed. |
-| choices | array of strings | `"ALL_KEYS"` | This array contains the key(s) that the participant is allowed to press in order to respond to the stimulus. Keys should be specified as characters (e.g., `'a'`, `'q'`, `' '`, `'Enter'`, `'ArrowDown'`) - see [this page](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values) and [this page (event.key column)](https://www.freecodecamp.org/news/javascript-keycode-list-keypress-event-key-codes/) for more examples. Any key presses that are not listed in the array will be ignored. The default value of `"ALL_KEYS"` means that all keys will be accepted as valid responses. Specifying `"NO_KEYS"` will mean that no responses are allowed. |
-| prompt | string | null | This string can contain HTML markup. Any content here will be displayed below the stimulus. The intention is that it can be used to provide a reminder about the action the participant is supposed to take (e.g., which key to press). |
-| stimulus_duration | numeric | null | How long to display the stimulus in milliseconds. The visibility CSS property of the stimulus will be set to `hidden` after this time has elapsed. If this is null, then the stimulus will remain visible until the trial ends. |
-| trial_duration | numeric | null | How long to wait for the participant to make a response before ending the trial in milliseconds. If the participant fails to make a response before this timer is reached, the participant's response will be recorded as null for the trial and the trial will end. If the value of this parameter is null, then the trial will wait for a response indefinitely. |
-| response_ends_trial | boolean | true | If true, then the trial will end whenever the participant makes a response (assuming they make their response before the cutoff specified by the `trial_duration` parameter). If false, then the trial will continue until the value for `trial_duration` is reached. You can set this parameter to `false` to force the participant to view a stimulus for a fixed amount of time, even if they respond before the time is complete. |
+{{ plugin_meta('html-keyboard-response') }}
+{{ plugin_description('html-keyboard-response') }}
+{{ plugin_parameters('html-keyboard-response') }}
## Data Generated
@@ -28,28 +14,7 @@ In addition to the [default data collected by all plugins](../overview/plugins.m
| rt | numeric | The response time in milliseconds for the participant to make a response. The time is measured from when the stimulus first appears on the screen until the participant's response. |
| stimulus | string | The HTML content that was displayed on the screen. |
-## Install
-
-Using the CDN-hosted JavaScript file:
-
-```js
-
-```
-
-Using the JavaScript file downloaded from a GitHub release dist archive:
-
-```js
-
-```
-
-Using NPM:
-
-```
-npm install @jspsych/plugin-html-keyboard-response
-```
-```js
-import htmlKeyboardResponse from '@jspsych/plugin-html-keyboard-response';
-```
+{{ plugin_installation('html-keyboard-response') }}
## Examples
diff --git a/mkdocs.yml b/mkdocs.yml
index b172c2993e..036ecbfaa9 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -38,6 +38,12 @@ repo_name: 'jspsych/jspsych'
edit_uri: edit/main/docs
site_url: 'https://www.jspsych.org/'
docs_dir: docs
+plugins:
+ - search
+ - macros:
+ modules: [docs]
+watch:
+ - packages
nav:
- Introduction: 'index.md'
- Tutorials:
diff --git a/package-lock.json b/package-lock.json
index cc7b542c71..0fccd2987d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -16,7 +16,8 @@
"lint-staged": "^13.0.3",
"prettier": "^2.7.1",
"prettier-plugin-import-sort": "^0.0.7",
- "turbo": "^1.6.3"
+ "turbo": "^1.6.3",
+ "typedoc": "^0.23.20"
}
},
"node_modules/@ampproject/remapping": {
@@ -11704,6 +11705,12 @@
"node": ">=10"
}
},
+ "node_modules/lunr": {
+ "version": "2.3.9",
+ "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz",
+ "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==",
+ "dev": true
+ },
"node_modules/magic-string": {
"version": "0.26.7",
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.26.7.tgz",
@@ -11777,6 +11784,18 @@
"node": ">=0.10.0"
}
},
+ "node_modules/marked": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/marked/-/marked-4.2.3.tgz",
+ "integrity": "sha512-slWRdJkbTZ+PjkyJnE30Uid64eHwbwa1Q25INCAYfZlK4o6ylagBy/Le9eWntqJFoFT93ikUKMv47GZ4gTwHkw==",
+ "dev": true,
+ "bin": {
+ "marked": "bin/marked.js"
+ },
+ "engines": {
+ "node": ">= 12"
+ }
+ },
"node_modules/matchdep": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/matchdep/-/matchdep-2.0.0.tgz",
@@ -14328,6 +14347,17 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/shiki": {
+ "version": "0.11.1",
+ "resolved": "https://registry.npmjs.org/shiki/-/shiki-0.11.1.tgz",
+ "integrity": "sha512-EugY9VASFuDqOexOgXR18ZV+TbFrQHeCpEYaXamO+SZlsnT/2LxuLBX25GGtIrwaEVFXUAbUQ601SWE2rMwWHA==",
+ "dev": true,
+ "dependencies": {
+ "jsonc-parser": "^3.0.0",
+ "vscode-oniguruma": "^1.6.1",
+ "vscode-textmate": "^6.0.0"
+ }
+ },
"node_modules/side-channel": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
@@ -16129,6 +16159,48 @@
"resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
"integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA=="
},
+ "node_modules/typedoc": {
+ "version": "0.23.21",
+ "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.23.21.tgz",
+ "integrity": "sha512-VNE9Jv7BgclvyH9moi2mluneSviD43dCE9pY8RWkO88/DrEgJZk9KpUk7WO468c9WWs/+aG6dOnoH7ccjnErhg==",
+ "dev": true,
+ "dependencies": {
+ "lunr": "^2.3.9",
+ "marked": "^4.0.19",
+ "minimatch": "^5.1.0",
+ "shiki": "^0.11.1"
+ },
+ "bin": {
+ "typedoc": "bin/typedoc"
+ },
+ "engines": {
+ "node": ">= 14.14"
+ },
+ "peerDependencies": {
+ "typescript": "4.6.x || 4.7.x || 4.8.x || 4.9.x"
+ }
+ },
+ "node_modules/typedoc/node_modules/brace-expansion": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+ "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+ "dev": true,
+ "dependencies": {
+ "balanced-match": "^1.0.0"
+ }
+ },
+ "node_modules/typedoc/node_modules/minimatch": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.0.tgz",
+ "integrity": "sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==",
+ "dev": true,
+ "dependencies": {
+ "brace-expansion": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
"node_modules/typescript": {
"version": "4.9.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.3.tgz",
@@ -16521,6 +16593,18 @@
"node": ">=0.10.0"
}
},
+ "node_modules/vscode-oniguruma": {
+ "version": "1.6.2",
+ "resolved": "https://registry.npmjs.org/vscode-oniguruma/-/vscode-oniguruma-1.6.2.tgz",
+ "integrity": "sha512-KH8+KKov5eS/9WhofZR8M8dMHWN2gTxjMsG4jd04YhpbPR91fUj7rYQ2/XjeHCJWbg7X++ApRIU9NUwM2vTvLA==",
+ "dev": true
+ },
+ "node_modules/vscode-textmate": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/vscode-textmate/-/vscode-textmate-6.0.0.tgz",
+ "integrity": "sha512-gu73tuZfJgu+mvCSy4UZwd2JXykjK9zAZsfmDeut5dx/1a7FeTk0XwJsSuqQn+cuMCGVbIBfl+s53X4T19DnzQ==",
+ "dev": true
+ },
"node_modules/vue-jscodeshift-adapter": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/vue-jscodeshift-adapter/-/vue-jscodeshift-adapter-2.2.0.tgz",
diff --git a/package.json b/package.json
index 9d1dfc568b..2b33fcc06c 100644
--- a/package.json
+++ b/package.json
@@ -17,7 +17,8 @@
"changeset:version": "changeset version && npm install && npm run update-unpkg-links && npm run update-plugin-versions",
"changeset:publish": "npm run build && changeset publish",
"docs:deploy": "poetry install && poetry run mike deploy -u",
- "docs:serve": "poetry install && poetry run mike serve"
+ "docs:serve": "poetry install && poetry run mike serve",
+ "docs:preview": "poetry run mkdocs serve"
},
"devDependencies": {
"@changesets/changelog-github": "^0.4.7",
@@ -28,7 +29,8 @@
"lint-staged": "^13.0.3",
"prettier": "^2.7.1",
"prettier-plugin-import-sort": "^0.0.7",
- "turbo": "^1.6.3"
+ "turbo": "^1.6.3",
+ "typedoc": "^0.23.20"
},
"prettier": {
"printWidth": 100
diff --git a/packages/plugin-audio-button-response/src/index.ts b/packages/plugin-audio-button-response/src/index.ts
index 942063164f..f28307fcab 100644
--- a/packages/plugin-audio-button-response/src/index.ts
+++ b/packages/plugin-audio-button-response/src/index.ts
@@ -3,65 +3,102 @@ import { JsPsych, JsPsychPlugin, ParameterType, TrialType } from "jspsych";
const info = {
name: "audio-button-response",
parameters: {
- /** The audio to be played. */
+ /** Path to audio file to be played. */
stimulus: {
type: ParameterType.AUDIO,
pretty_name: "Stimulus",
default: undefined,
},
- /** Array containing the label(s) for the button(s). */
+
+ /**
+ * Labels for the buttons. Each different string in the array will generate a different button.
+ */
choices: {
type: ParameterType.STRING,
pretty_name: "Choices",
default: undefined,
array: true,
},
- /** The HTML for creating button. Can create own style. Use the "%choice%" string to indicate where the label from the choices parameter should be inserted. */
+
+ /**
+ * A template of HTML for generating the button elements. You can override this to create
+ * customized buttons of various kinds. The string `%choice%` will be changed to the
+ * corresponding element of the `choices` array. You may also specify an array of strings, if
+ * you need different HTML to render for each button. If you do specify an array, the `choices`
+ * array and this array must have the same length. The HTML from position 0 in the `button_html`
+ * array will be used to create the button for element 0 in the `choices` array, and so on.
+ **/
button_html: {
type: ParameterType.HTML_STRING,
pretty_name: "Button HTML",
default: '',
array: true,
},
- /** Any content here will be displayed below the stimulus. */
+
+ /**
+ * This string can contain HTML markup. Any content here will be displayed below the stimulus.
+ * The intention is that it can be used to provide a reminder about the action the participant
+ * is supposed to take (e.g., which key to press).
+ */
prompt: {
type: ParameterType.HTML_STRING,
pretty_name: "Prompt",
default: null,
},
- /** The maximum duration to wait for a response. */
+
+ /**
+ * How long to wait for the participant to make a response before ending the trial in
+ * milliseconds. If the participant fails to make a response before this timer is reached, the
+ * participant's response will be recorded as null for the trial and the trial will end. If the
+ * value of this parameter is null, the trial will wait for a response indefinitely.
+ */
trial_duration: {
type: ParameterType.INT,
pretty_name: "Trial duration",
default: null,
},
- /** Vertical margin of button. */
+
+ /** Vertical margin of the button(s). */
margin_vertical: {
type: ParameterType.STRING,
pretty_name: "Margin vertical",
default: "0px",
},
- /** Horizontal margin of button. */
+
+ /** Horizontal margin of the button(s). */
margin_horizontal: {
type: ParameterType.STRING,
pretty_name: "Margin horizontal",
default: "8px",
},
- /** If true, the trial will end when user makes a response. */
+
+ /**
+ * If true, then the trial will end whenever the participant makes a response (assuming they
+ * make their response before the cutoff specified by the `trial_duration` parameter). If false,
+ * then the trial will continue until the value for `trial_duration` is reached. You can set
+ * this parameter to `false` to force the participant to listen to the stimulus for a fixed
+ * amount of time, even if they respond before the time is complete.
+ */
response_ends_trial: {
type: ParameterType.BOOL,
pretty_name: "Response ends trial",
default: true,
},
- /** If true, then the trial will end as soon as the audio file finishes playing. */
+
+ /**
+ * If true, then the trial will end as soon as the audio file finishes playing.
+ */
trial_ends_after_audio: {
type: ParameterType.BOOL,
pretty_name: "Trial ends after audio",
default: false,
},
+
/**
- * If true, then responses are allowed while the audio is playing.
- * If false, then the audio must finish playing before a response is accepted.
+ * If true, then responses are allowed while the audio is playing. If false, then the audio must
+ * finish playing before the button choices are enabled and a response is accepted. Once the
+ * audio has played all the way through, the buttons are enabled and a response is allowed
+ * (including while the audio is being re-played via on-screen playback controls).
*/
response_allowed_while_playing: {
type: ParameterType.BOOL,
@@ -74,12 +111,26 @@ const info = {
type Info = typeof info;
/**
- * **audio-button-response**
+ * This plugin plays audio files and records responses generated with a button click.
+ *
+ * If the browser supports it, audio files are played using the WebAudio API. This allows for
+ * reasonably precise timing of the playback. The timing of responses generated is measured against
+ * the WebAudio specific clock, improving the measurement of response times. If the browser does not
+ * support the WebAudio API, then the audio file is played with HTML5 audio.
+ *
+ * Audio files can be automatically preloaded by jsPsych using the [`preload` plugin](preload.md).
+ * However, if you are using timeline variables or another dynamic method to specify the audio
+ * stimulus, you will need to [manually preload](../overview/media-preloading.md#manual-preloading)
+ * the audio.
+ *
+ * The trial can end when the participant responds, when the audio file has finished playing, or if
+ * the participant has failed to respond within a fixed length of time. You can also prevent a
+ * button response from being made before the audio has finished playing.
*
- * jsPsych plugin for playing an audio file and getting a button response
*
* @author Kristin Diep
- * @see {@link https://www.jspsych.org/plugins/jspsych-audio-button-response/ audio-button-response plugin documentation on jspsych.org}
+ * @see
+ {@link https://www.jspsych.org/latest/plugins/jspsych-audio-button-response/}
*/
class AudioButtonResponsePlugin implements JsPsychPlugin {
static info = info;
diff --git a/packages/plugin-browser-check/src/index.ts b/packages/plugin-browser-check/src/index.ts
index 4fb0b7dbda..e9fdfe6d42 100644
--- a/packages/plugin-browser-check/src/index.ts
+++ b/packages/plugin-browser-check/src/index.ts
@@ -5,7 +5,8 @@ const info = {
name: "browser-check",
parameters: {
/**
- * List of features to check and record in the data
+ * The list of browser features to record. The default value includes all of the available
+ * options.
*/
features: {
type: ParameterType.STRING,
@@ -24,51 +25,74 @@ const info = {
"microphone",
],
},
+
/**
- * Any features listed here will be skipped, even if they appear in `features`. Useful for
- * when you want to run most of the defaults.
+ * Any features listed here will be skipped, even if they appear in `features`. Use this when
+ * you want to run most of the defaults.
*/
skip_features: {
type: ParameterType.STRING,
array: true,
default: [],
},
+
/**
- * The number of animation frames to sample when calculating vsync_rate.
+ * The number of frames to sample when measuring the display refresh rate (`"vsync_rate"`).
+ * Increasing the number will potenially improve the stability of the estimate at the cost of
+ * increasing the amount of time the plugin takes during this test. On most devices, 60 frames
+ * takes about 1 second to measure.
*/
vsync_frame_count: {
type: ParameterType.INT,
default: 60,
},
+
/**
- * If `true`, show a message when window size is too small to allow the user
- * to adjust if their screen allows for it.
+ * Whether to allow the participant to resize the browser window if the window is smaller than
+ * `minimum_width` and/or `minimum_height`. If `false`, then the `minimum_width` and
+ * `minimum_height` parameters are ignored and you can validate the size in the
+ * `inclusion_function`.
*/
allow_window_resize: {
type: ParameterType.BOOL,
default: true,
},
+
/**
- * When `allow_window_resize` is `true`, this is the minimum width (px) that the window
- * needs to be before the experiment will continue.
+ * If `allow_window_resize` is `true`, then this is the minimum width of the window (in pixels)
+ * that must be met before continuing.
*/
minimum_width: {
type: ParameterType.INT,
default: 0,
},
+
/**
- * When `allow_window_resize` is `true`, this is the minimum height (px) that the window
- * needs to be before the experiment will continue.
+ * If `allow_window_resize` is `true`, then this is the minimum height of the window (in pixels)
+ * that must be met before continuing.
*/
minimum_height: {
type: ParameterType.INT,
default: 0,
},
+
/**
- * Message to display during interactive window resizing.
+ * The message that will be displayed during the interactive resize when `allow_window_resize`
+ * is `true` and the window is too small. If the message contains HTML elements with the special
+ * IDs `browser-check-min-width`, `browser-check-min-height`, `browser-check-actual-height`,
+ * and/or `browser-check-actual-width`, then the contents of those elements will be dynamically
+ * updated to reflect the `minimum_width`, `minimum_height` and measured width and height of the
+ * browser. The default message is: `
Your browser window is too small to complete this
+ * experiment. Please maximize the size of your browser window. If your browser window is
+ * already maximized, you will not be able to complete this experiment.
Your browser window is too small to complete this experiment. Please maximize the size of your browser window.
If your browser window is already maximized, you will not be able to complete this experiment.
The minimum window width is px.
@@ -76,33 +100,50 @@ const info = {
The minimum window height is px.
Your current window height is px.
`,
},
+
/**
* During the interactive resize, a button with this text will be displayed below the
- * `window_resize_message` for the participant to click if the window cannot meet the
- * minimum size needed. When the button is clicked, the experiment will end and
- * `exclusion_message` will be displayed.
+ * `window_resize_message` for the participant to click if the window cannot meet the minimum
+ * size needed. When the button is clicked, the experiment will end and `exclusion_message` will
+ * be displayed.
*/
resize_fail_button_text: {
type: ParameterType.STRING,
default: "I cannot make the window any larger",
},
+
/**
- * A function that evaluates to `true` if the browser meets all of the inclusion criteria
- * for the experiment, and `false` otherwise. The first argument to the function will be
- * an object containing key value pairs with the measured features of the browser. The
- * keys will be the same as those listed in `features`.
+ * A function that evaluates to `true` if the browser meets all of the inclusion criteria for
+ * the experiment, and `false` otherwise. The first argument to the function will be an object
+ * containing key value pairs with the measured features of the browser. The keys will be the
+ * same as those listed in `features`. See example below.
*/
inclusion_function: {
type: ParameterType.FUNCTION,
+ /**
+ * ```
+ * () => true
+ * ```
+ */
default: () => {
return true;
},
},
+
/**
- * The message to display if `inclusion_function` returns `false`
+ * A function that returns the message to display if `inclusion_function` evaluates to `false`
+ * or if the participant clicks on the resize fail button during the interactive resize. In
+ * order to allow customization of the message, the first argument to the function will be an
+ * object containing key value pairs with the measured features of the browser. The keys will be
+ * the same as those listed in `features`. See example below.
*/
exclusion_message: {
type: ParameterType.FUNCTION,
+ /**
+ * ```
+ * () => `
Your browser does not meet the requirements to participate in this experiment.
`
+ * ```
+ */
default: () => {
return `
Your browser does not meet the requirements to participate in this experiment.
`;
},
@@ -113,12 +154,42 @@ const info = {
type Info = typeof info;
/**
- * **browser-check**
+ * This plugin measures and records various features of the participant's browser and can end the
+ * experiment if defined inclusion criteria are not met.
+ *
+ * The plugin currently can record the following features:
+ *
+ * * The width and height of the browser window in pixels.
+ * * The type of browser used (e.g., Chrome, Firefox, Edge, etc.) and the version number of the
+ * browser.*
+ * * Whether the participant is using a mobile device.*
+ * * The operating system.*
+ * * Support for the WebAudio API.
+ * * Support for the Fullscreen API, e.g., through the [fullscreen
+ * plugin](../plugins/fullscreen.md).
+ * * The display refresh rate in frames per second.
+ * * Whether the device has a webcam and microphone. Note that this only reveals whether a
+ * webcam/microphone exists. The participant still needs to grant permission in order for the
+ * experiment to use these devices.
+ *
+ * > **Warning**
+ * >
+ * > Features with an * are recorded by parsing the [user agent
+ * > string](https://developer.mozilla.org/en-US/docs/Web/HTTP/Browser_detection_using_the_user_agent).
+ * > This method is accurate most of the time, but is not guaranteed to be correct. The plugin uses
+ * > the [detect-browser package](https://github.com/DamonOehlman/detect-browser) to perform user
+ * > agent parsing. You can find a list of supported browsers and OSes in the [source
+ * > file](https://github.com/DamonOehlman/detect-browser/blob/master/src/index.ts).
*
- * jsPsych plugin for checking features of the browser and validating against a set of inclusion criteria.
+ * The plugin begins by measuring the set of features requested. An inclusion function is evaluated
+ * to see if the paricipant passes the inclusion criteria. If they do, then the trial ends and the
+ * experiment continues. If they do not, then the experiment ends immediately. If a minimum width
+ * and/or minimum height is desired, the plugin will optionally display a message to participants
+ * whose browser windows are too small to give them an opportunity to make the window larger if
+ * possible. See the examples below for more guidance.
*
* @author Josh de Leeuw
- * @see {@link https://www.jspsych.org/plugins/jspsych-browser-check/ browser-check plugin documentation on jspsych.org}
+ * @see {@link https://www.jspsych.org/latest/plugins/jspsych-browser-check/}
*/
class BrowserCheckPlugin implements JsPsychPlugin {
static info = info;
diff --git a/packages/plugin-html-keyboard-response/src/index.ts b/packages/plugin-html-keyboard-response/src/index.ts
index d086ea5616..fecaa79e2f 100644
--- a/packages/plugin-html-keyboard-response/src/index.ts
+++ b/packages/plugin-html-keyboard-response/src/index.ts
@@ -11,40 +11,66 @@ const info = {
pretty_name: "Stimulus",
default: undefined,
},
+
/**
- * Array containing the key(s) the subject is allowed to press to respond to the stimulus.
+ * This array contains the key(s) that the participant is allowed to press in order to respond
+ * to the stimulus. Keys should be specified as characters (e.g., `'a'`, `'q'`, `' '`,
+ * `'Enter'`, `'ArrowDown'`) - see
+ * {@link https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values this page}
+ * and
+ * {@link https://www.freecodecamp.org/news/javascript-keycode-list-keypress-event-key-codes/ this page}
+ * (event.key column) for more examples.
+ *
+ * Any key presses that are not listed in the array will be ignored. The default value of
+ * `"ALL_KEYS"` means that all keys will be accepted as valid responses. Specifying `"NO_KEYS"`
+ * will mean that no responses are allowed.
*/
choices: {
type: ParameterType.KEYS,
pretty_name: "Choices",
default: "ALL_KEYS",
},
+
/**
- * Any content here will be displayed below the stimulus.
+ * This string can contain HTML markup. Any content here will be displayed below the stimulus.
+ * The intention is that it can be used to provide a reminder about the action the participant
+ * is supposed to take (e.g., which key to press).
*/
prompt: {
type: ParameterType.HTML_STRING,
pretty_name: "Prompt",
default: null,
},
+
/**
- * How long to show the stimulus.
+ * How long to display the stimulus in milliseconds. The visibility CSS property of the stimulus
+ * will be set to `hidden` after this time has elapsed. If this is null, then the stimulus will
+ * remain visible until the trial ends.
*/
stimulus_duration: {
type: ParameterType.INT,
pretty_name: "Stimulus duration",
default: null,
},
+
/**
- * How long to show trial before it ends.
+ * How long to wait for the participant to make a response before ending the trial in
+ * milliseconds. If the participant fails to make a response before this timer is reached, the
+ * participant's response will be recorded as null for the trial and the trial will end. If the
+ * value of this parameter is null, then the trial will wait for a response indefinitely.
*/
trial_duration: {
type: ParameterType.INT,
pretty_name: "Trial duration",
default: null,
},
+
/**
- * If true, trial will end when subject makes a response.
+ * If true, then the trial will end whenever the participant makes a response (assuming they
+ * make their response before the cutoff specified by the `trial_duration` parameter). If false,
+ * then the trial will continue until the value for `trial_duration` is reached. You can set
+ * this parameter to `false` to force the participant to view a stimulus for a fixed amount of
+ * time, even if they respond before the time is complete.
*/
response_ends_trial: {
type: ParameterType.BOOL,
@@ -57,12 +83,12 @@ const info = {
type Info = typeof info;
/**
- * **html-keyboard-response**
- *
- * jsPsych plugin for displaying a stimulus and getting a keyboard response
+ * This plugin displays HTML content and records responses generated with the keyboard. The stimulus
+ * can be displayed until a response is given, or for a pre-determined amount of time. The trial can
+ * be ended automatically if the participant has failed to respond within a fixed length of time.
*
* @author Josh de Leeuw
- * @see {@link https://www.jspsych.org/plugins/jspsych-html-keyboard-response/ html-keyboard-response plugin documentation on jspsych.org}
+ * @see {@link https://www.jspsych.org/latest/plugins/jspsych-html-keyboard-response/}
*/
class HtmlKeyboardResponsePlugin implements JsPsychPlugin {
static info = info;
diff --git a/poetry.lock b/poetry.lock
index e6cb078902..b27ec9fb80 100644
--- a/poetry.lock
+++ b/poetry.lock
@@ -1,3 +1,44 @@
+[[package]]
+name = "black"
+version = "22.10.0"
+description = "The uncompromising code formatter."
+category = "dev"
+optional = false
+python-versions = ">=3.7"
+
+[package.dependencies]
+click = ">=8.0.0"
+mypy-extensions = ">=0.4.3"
+pathspec = ">=0.9.0"
+platformdirs = ">=2"
+tomli = {version = ">=1.1.0", markers = "python_full_version < \"3.11.0a7\""}
+typing-extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""}
+
+[package.extras]
+colorama = ["colorama (>=0.4.3)"]
+d = ["aiohttp (>=3.7.4)"]
+jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"]
+uvloop = ["uvloop (>=0.15.2)"]
+
+[[package]]
+name = "certifi"
+version = "2022.9.24"
+description = "Python package for providing Mozilla's CA Bundle."
+category = "main"
+optional = false
+python-versions = ">=3.6"
+
+[[package]]
+name = "charset-normalizer"
+version = "2.1.1"
+description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
+category = "main"
+optional = false
+python-versions = ">=3.6.0"
+
+[package.extras]
+unicode-backport = ["unicodedata2"]
+
[[package]]
name = "click"
version = "8.1.3"
@@ -17,6 +58,22 @@ category = "dev"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
+[[package]]
+name = "decorator"
+version = "5.1.1"
+description = "Decorators for Humans"
+category = "dev"
+optional = false
+python-versions = ">=3.5"
+
+[[package]]
+name = "diskcache"
+version = "5.4.0"
+description = "Disk Cache -- Disk and file backed persistent cache."
+category = "main"
+optional = false
+python-versions = ">=3"
+
[[package]]
name = "ghp-import"
version = "2.1.0"
@@ -29,7 +86,15 @@ python-versions = "*"
python-dateutil = ">=2.8.1"
[package.extras]
-dev = ["twine", "markdown", "flake8", "wheel"]
+dev = ["flake8", "markdown", "twine", "wheel"]
+
+[[package]]
+name = "idna"
+version = "3.4"
+description = "Internationalized Domain Names in Applications (IDNA)"
+category = "main"
+optional = false
+python-versions = ">=3.5"
[[package]]
name = "importlib-metadata"
@@ -43,9 +108,23 @@ python-versions = ">=3.7"
zipp = ">=0.5"
[package.extras]
-docs = ["sphinx", "jaraco.packaging (>=9)", "rst.linker (>=1.9)"]
+docs = ["jaraco.packaging (>=9)", "rst.linker (>=1.9)", "sphinx"]
perf = ["ipython"]
-testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "packaging", "pyfakefs", "flufl.flake8", "pytest-perf (>=0.9.2)", "pytest-black (>=0.3.7)", "pytest-mypy (>=0.9.1)", "importlib-resources (>=1.3)"]
+testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.0.1)", "pytest-flake8", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)"]
+
+[[package]]
+name = "isort"
+version = "5.10.1"
+description = "A Python utility / library to sort Python imports."
+category = "dev"
+optional = false
+python-versions = ">=3.6.1,<4.0"
+
+[package.extras]
+colors = ["colorama (>=0.4.3,<0.5.0)"]
+pipfile-deprecated-finder = ["pipreqs", "requirementslib"]
+plugins = ["setuptools"]
+requirements-deprecated-finder = ["pip-api", "pipreqs"]
[[package]]
name = "jinja2"
@@ -61,6 +140,19 @@ MarkupSafe = ">=2.0"
[package.extras]
i18n = ["Babel (>=2.7)"]
+[[package]]
+name = "jsonpath-ng"
+version = "1.5.3"
+description = "A final implementation of JSONPath for Python that aims to be standard compliant, including arithmetic and binary comparison operators and providing clear AST for metaprogramming."
+category = "dev"
+optional = false
+python-versions = "*"
+
+[package.dependencies]
+decorator = "*"
+ply = "*"
+six = "*"
+
[[package]]
name = "markdown"
version = "3.3.7"
@@ -132,6 +224,24 @@ watchdog = ">=2.0"
[package.extras]
i18n = ["babel (>=2.9.0)"]
+[[package]]
+name = "mkdocs-macros-plugin"
+version = "0.7.0"
+description = "Unleash the power of MkDocs with macros and variables"
+category = "dev"
+optional = false
+python-versions = ">=3.5"
+
+[package.dependencies]
+jinja2 = "*"
+mkdocs = ">=0.17"
+python-dateutil = "*"
+pyyaml = "*"
+termcolor = "*"
+
+[package.extras]
+test = ["mkdocs-include-markdown-plugin", "mkdocs-macros-test", "mkdocs-material (>=6.2)"]
+
[[package]]
name = "mkdocs-material"
version = "8.2.15"
@@ -156,6 +266,14 @@ category = "dev"
optional = false
python-versions = ">=3.6"
+[[package]]
+name = "mypy-extensions"
+version = "0.4.3"
+description = "Experimental type system extensions for programs checked with the mypy typechecker."
+category = "dev"
+optional = false
+python-versions = "*"
+
[[package]]
name = "packaging"
version = "21.3"
@@ -167,6 +285,34 @@ python-versions = ">=3.6"
[package.dependencies]
pyparsing = ">=2.0.2,<3.0.5 || >3.0.5"
+[[package]]
+name = "pathspec"
+version = "0.10.2"
+description = "Utility library for gitignore style pattern matching of file paths."
+category = "dev"
+optional = false
+python-versions = ">=3.7"
+
+[[package]]
+name = "platformdirs"
+version = "2.5.4"
+description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"."
+category = "dev"
+optional = false
+python-versions = ">=3.7"
+
+[package.extras]
+docs = ["furo (>=2022.9.29)", "proselint (>=0.13)", "sphinx (>=5.3)", "sphinx-autodoc-typehints (>=1.19.4)"]
+test = ["appdirs (==1.4.4)", "pytest (>=7.2)", "pytest-cov (>=4)", "pytest-mock (>=3.10)"]
+
+[[package]]
+name = "ply"
+version = "3.11"
+description = "Python Lex & Yacc"
+category = "dev"
+optional = false
+python-versions = "*"
+
[[package]]
name = "pygments"
version = "2.12.0"
@@ -195,7 +341,7 @@ optional = false
python-versions = ">=3.6.8"
[package.extras]
-diagrams = ["railroad-diagrams", "jinja2"]
+diagrams = ["jinja2", "railroad-diagrams"]
[[package]]
name = "python-dateutil"
@@ -227,6 +373,24 @@ python-versions = ">=3.6"
[package.dependencies]
pyyaml = "*"
+[[package]]
+name = "requests"
+version = "2.28.1"
+description = "Python HTTP for Humans."
+category = "main"
+optional = false
+python-versions = ">=3.7, <4"
+
+[package.dependencies]
+certifi = ">=2017.4.17"
+charset-normalizer = ">=2,<3"
+idna = ">=2.5,<4"
+urllib3 = ">=1.21.1,<1.27"
+
+[package.extras]
+socks = ["PySocks (>=1.5.6,!=1.5.7)"]
+use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"]
+
[[package]]
name = "six"
version = "1.16.0"
@@ -235,6 +399,46 @@ category = "dev"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
+[[package]]
+name = "termcolor"
+version = "2.1.0"
+description = "ANSI color formatting for output in terminal"
+category = "dev"
+optional = false
+python-versions = ">=3.7"
+
+[package.extras]
+tests = ["pytest", "pytest-cov"]
+
+[[package]]
+name = "tomli"
+version = "2.0.1"
+description = "A lil' TOML parser"
+category = "dev"
+optional = false
+python-versions = ">=3.7"
+
+[[package]]
+name = "typing-extensions"
+version = "4.4.0"
+description = "Backported and Experimental Type Hints for Python 3.7+"
+category = "dev"
+optional = false
+python-versions = ">=3.7"
+
+[[package]]
+name = "urllib3"
+version = "1.26.13"
+description = "HTTP library with thread-safe connection pooling, file post, and more."
+category = "main"
+optional = false
+python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*"
+
+[package.extras]
+brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"]
+secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"]
+socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"]
+
[[package]]
name = "verspec"
version = "0.1.0"
@@ -266,15 +470,46 @@ optional = false
python-versions = ">=3.7"
[package.extras]
-docs = ["sphinx", "jaraco.packaging (>=9)", "rst.linker (>=1.9)"]
-testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy (>=0.9.1)"]
+docs = ["jaraco.packaging (>=9)", "rst.linker (>=1.9)", "sphinx"]
+testing = ["func-timeout", "jaraco.itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.0.1)", "pytest-flake8", "pytest-mypy (>=0.9.1)"]
[metadata]
lock-version = "1.1"
python-versions = "^3.8"
-content-hash = "cc64c57c4358cb845e18c37da5e3e79186e5cc93d3b16d608b2503aa9376f5f4"
+content-hash = "10332520403d432b0488a65490d6041d20520490ad30d3fb0807a27774c37416"
[metadata.files]
+black = [
+ {file = "black-22.10.0-1fixedarch-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:5cc42ca67989e9c3cf859e84c2bf014f6633db63d1cbdf8fdb666dcd9e77e3fa"},
+ {file = "black-22.10.0-1fixedarch-cp311-cp311-macosx_11_0_x86_64.whl", hash = "sha256:5d8f74030e67087b219b032aa33a919fae8806d49c867846bfacde57f43972ef"},
+ {file = "black-22.10.0-1fixedarch-cp37-cp37m-macosx_10_16_x86_64.whl", hash = "sha256:197df8509263b0b8614e1df1756b1dd41be6738eed2ba9e9769f3880c2b9d7b6"},
+ {file = "black-22.10.0-1fixedarch-cp38-cp38-macosx_10_16_x86_64.whl", hash = "sha256:2644b5d63633702bc2c5f3754b1b475378fbbfb481f62319388235d0cd104c2d"},
+ {file = "black-22.10.0-1fixedarch-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:e41a86c6c650bcecc6633ee3180d80a025db041a8e2398dcc059b3afa8382cd4"},
+ {file = "black-22.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2039230db3c6c639bd84efe3292ec7b06e9214a2992cd9beb293d639c6402edb"},
+ {file = "black-22.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14ff67aec0a47c424bc99b71005202045dc09270da44a27848d534600ac64fc7"},
+ {file = "black-22.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:819dc789f4498ecc91438a7de64427c73b45035e2e3680c92e18795a839ebb66"},
+ {file = "black-22.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5b9b29da4f564ba8787c119f37d174f2b69cdfdf9015b7d8c5c16121ddc054ae"},
+ {file = "black-22.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8b49776299fece66bffaafe357d929ca9451450f5466e997a7285ab0fe28e3b"},
+ {file = "black-22.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:21199526696b8f09c3997e2b4db8d0b108d801a348414264d2eb8eb2532e540d"},
+ {file = "black-22.10.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1e464456d24e23d11fced2bc8c47ef66d471f845c7b7a42f3bd77bf3d1789650"},
+ {file = "black-22.10.0-cp37-cp37m-win_amd64.whl", hash = "sha256:9311e99228ae10023300ecac05be5a296f60d2fd10fff31cf5c1fa4ca4b1988d"},
+ {file = "black-22.10.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:fba8a281e570adafb79f7755ac8721b6cf1bbf691186a287e990c7929c7692ff"},
+ {file = "black-22.10.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:915ace4ff03fdfff953962fa672d44be269deb2eaf88499a0f8805221bc68c87"},
+ {file = "black-22.10.0-cp38-cp38-win_amd64.whl", hash = "sha256:444ebfb4e441254e87bad00c661fe32df9969b2bf224373a448d8aca2132b395"},
+ {file = "black-22.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:974308c58d057a651d182208a484ce80a26dac0caef2895836a92dd6ebd725e0"},
+ {file = "black-22.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:72ef3925f30e12a184889aac03d77d031056860ccae8a1e519f6cbb742736383"},
+ {file = "black-22.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:432247333090c8c5366e69627ccb363bc58514ae3e63f7fc75c54b1ea80fa7de"},
+ {file = "black-22.10.0-py3-none-any.whl", hash = "sha256:c957b2b4ea88587b46cf49d1dc17681c1e672864fd7af32fc1e9664d572b3458"},
+ {file = "black-22.10.0.tar.gz", hash = "sha256:f513588da599943e0cde4e32cc9879e825d58720d6557062d1098c5ad80080e1"},
+]
+certifi = [
+ {file = "certifi-2022.9.24-py3-none-any.whl", hash = "sha256:90c1a32f1d68f940488354e36370f6cca89f0f106db09518524c88d6ed83f382"},
+ {file = "certifi-2022.9.24.tar.gz", hash = "sha256:0d9c601124e5a6ba9712dbc60d9c53c21e34f5f641fe83002317394311bdce14"},
+]
+charset-normalizer = [
+ {file = "charset-normalizer-2.1.1.tar.gz", hash = "sha256:5a3d016c7c547f69d6f81fb0db9449ce888b418b5b9952cc5e6e66843e9dd845"},
+ {file = "charset_normalizer-2.1.1-py3-none-any.whl", hash = "sha256:83e9a75d1911279afd89352c68b45348559d1fc0506b054b346651b5e7fee29f"},
+]
click = [
{file = "click-8.1.3-py3-none-any.whl", hash = "sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48"},
{file = "click-8.1.3.tar.gz", hash = "sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e"},
@@ -283,18 +518,39 @@ colorama = [
{file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"},
{file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"},
]
+decorator = [
+ {file = "decorator-5.1.1-py3-none-any.whl", hash = "sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186"},
+ {file = "decorator-5.1.1.tar.gz", hash = "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330"},
+]
+diskcache = [
+ {file = "diskcache-5.4.0-py3-none-any.whl", hash = "sha256:af3ec6d7f167bbef7b6c33d9ee22f86d3e8f2dd7131eb7c4703d8d91ccdc0cc4"},
+ {file = "diskcache-5.4.0.tar.gz", hash = "sha256:8879eb8c9b4a2509a5e633d2008634fb2b0b35c2b36192d89655dbde02419644"},
+]
ghp-import = [
{file = "ghp-import-2.1.0.tar.gz", hash = "sha256:9c535c4c61193c2df8871222567d7fd7e5014d835f97dc7b7439069e2413d343"},
{file = "ghp_import-2.1.0-py3-none-any.whl", hash = "sha256:8337dd7b50877f163d4c0289bc1f1c7f127550241988d568c1db512c4324a619"},
]
+idna = [
+ {file = "idna-3.4-py3-none-any.whl", hash = "sha256:90b77e79eaa3eba6de819a0c442c0b4ceefc341a7a2ab77d7562bf49f425c5c2"},
+ {file = "idna-3.4.tar.gz", hash = "sha256:814f528e8dead7d329833b91c5faa87d60bf71824cd12a7530b5526063d02cb4"},
+]
importlib-metadata = [
{file = "importlib_metadata-4.11.3-py3-none-any.whl", hash = "sha256:1208431ca90a8cca1a6b8af391bb53c1a2db74e5d1cef6ddced95d4b2062edc6"},
{file = "importlib_metadata-4.11.3.tar.gz", hash = "sha256:ea4c597ebf37142f827b8f39299579e31685c31d3a438b59f469406afd0f2539"},
]
+isort = [
+ {file = "isort-5.10.1-py3-none-any.whl", hash = "sha256:6f62d78e2f89b4500b080fe3a81690850cd254227f27f75c3a0c491a1f351ba7"},
+ {file = "isort-5.10.1.tar.gz", hash = "sha256:e8443a5e7a020e9d7f97f1d7d9cd17c88bcb3bc7e218bf9cf5095fe550be2951"},
+]
jinja2 = [
{file = "Jinja2-3.1.2-py3-none-any.whl", hash = "sha256:6088930bfe239f0e6710546ab9c19c9ef35e29792895fed6e6e31a023a182a61"},
{file = "Jinja2-3.1.2.tar.gz", hash = "sha256:31351a702a408a9e7595a8fc6150fc3f43bb6bf7e319770cbc0db9df9437e852"},
]
+jsonpath-ng = [
+ {file = "jsonpath-ng-1.5.3.tar.gz", hash = "sha256:a273b182a82c1256daab86a313b937059261b5c5f8c4fa3fc38b882b344dd567"},
+ {file = "jsonpath_ng-1.5.3-py2-none-any.whl", hash = "sha256:f75b95dbecb8a0f3b86fd2ead21c2b022c3f5770957492b9b6196ecccfeb10aa"},
+ {file = "jsonpath_ng-1.5.3-py3-none-any.whl", hash = "sha256:292a93569d74029ba75ac2dc3d3630fc0e17b2df26119a165fa1d498ca47bf65"},
+]
markdown = [
{file = "Markdown-3.3.7-py3-none-any.whl", hash = "sha256:f5da449a6e1c989a4cea2631aa8ee67caa5a2ef855d551c88f9e309f4634c621"},
{file = "Markdown-3.3.7.tar.gz", hash = "sha256:cbb516f16218e643d8e0a95b309f77eb118cb138d39a4f27851e6a63581db874"},
@@ -353,6 +609,10 @@ mkdocs = [
{file = "mkdocs-1.3.0-py3-none-any.whl", hash = "sha256:26bd2b03d739ac57a3e6eed0b7bcc86168703b719c27b99ad6ca91dc439aacde"},
{file = "mkdocs-1.3.0.tar.gz", hash = "sha256:b504405b04da38795fec9b2e5e28f6aa3a73bb0960cb6d5d27ead28952bd35ea"},
]
+mkdocs-macros-plugin = [
+ {file = "mkdocs-macros-plugin-0.7.0.tar.gz", hash = "sha256:9e64e1cabcf6925359de29fe54f62d5847fb455c2528c440b87f8f1240650608"},
+ {file = "mkdocs_macros_plugin-0.7.0-py3-none-any.whl", hash = "sha256:96bdabeb98b96139544f0048ea2f5cb80c7befde6b21e94c6d4596c22774cbcf"},
+]
mkdocs-material = [
{file = "mkdocs-material-8.2.15.tar.gz", hash = "sha256:93b57e53733051431cc83216446e774bdf08bf516a6251ff2f24974f45f98149"},
{file = "mkdocs_material-8.2.15-py2.py3-none-any.whl", hash = "sha256:9d6c4ca1ceecc00b2e38c214665ed7605d275321dcaa22f38b9d1175edc58955"},
@@ -361,10 +621,26 @@ mkdocs-material-extensions = [
{file = "mkdocs-material-extensions-1.0.3.tar.gz", hash = "sha256:bfd24dfdef7b41c312ede42648f9eb83476ea168ec163b613f9abd12bbfddba2"},
{file = "mkdocs_material_extensions-1.0.3-py3-none-any.whl", hash = "sha256:a82b70e533ce060b2a5d9eb2bc2e1be201cf61f901f93704b4acf6e3d5983a44"},
]
+mypy-extensions = [
+ {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"},
+ {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"},
+]
packaging = [
{file = "packaging-21.3-py3-none-any.whl", hash = "sha256:ef103e05f519cdc783ae24ea4e2e0f508a9c99b2d4969652eed6a2e1ea5bd522"},
{file = "packaging-21.3.tar.gz", hash = "sha256:dd47c42927d89ab911e606518907cc2d3a1f38bbd026385970643f9c5b8ecfeb"},
]
+pathspec = [
+ {file = "pathspec-0.10.2-py3-none-any.whl", hash = "sha256:88c2606f2c1e818b978540f73ecc908e13999c6c3a383daf3705652ae79807a5"},
+ {file = "pathspec-0.10.2.tar.gz", hash = "sha256:8f6bf73e5758fd365ef5d58ce09ac7c27d2833a8d7da51712eac6e27e35141b0"},
+]
+platformdirs = [
+ {file = "platformdirs-2.5.4-py3-none-any.whl", hash = "sha256:af0276409f9a02373d540bf8480021a048711d572745aef4b7842dad245eba10"},
+ {file = "platformdirs-2.5.4.tar.gz", hash = "sha256:1006647646d80f16130f052404c6b901e80ee4ed6bef6792e1f238a8969106f7"},
+]
+ply = [
+ {file = "ply-3.11-py2.py3-none-any.whl", hash = "sha256:096f9b8350b65ebd2fd1346b12452efe5b9607f7482813ffca50c22722a807ce"},
+ {file = "ply-3.11.tar.gz", hash = "sha256:00c7c1aaa88358b9c765b6d3000c6eec0ba42abca5351b095321aef446081da3"},
+]
pygments = [
{file = "Pygments-2.12.0-py3-none-any.whl", hash = "sha256:dc9c10fb40944260f6ed4c688ece0cd2048414940f1cea51b8b226318411c519"},
{file = "Pygments-2.12.0.tar.gz", hash = "sha256:5eb116118f9612ff1ee89ac96437bb6b49e8f04d8a13b514ba26f620208e26eb"},
@@ -389,6 +665,13 @@ pyyaml = [
{file = "PyYAML-6.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5"},
{file = "PyYAML-6.0-cp310-cp310-win32.whl", hash = "sha256:2cd5df3de48857ed0544b34e2d40e9fac445930039f3cfe4bcc592a1f836d513"},
{file = "PyYAML-6.0-cp310-cp310-win_amd64.whl", hash = "sha256:daf496c58a8c52083df09b80c860005194014c3698698d1a57cbcfa182142a3a"},
+ {file = "PyYAML-6.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d4b0ba9512519522b118090257be113b9468d804b19d63c71dbcf4a48fa32358"},
+ {file = "PyYAML-6.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:81957921f441d50af23654aa6c5e5eaf9b06aba7f0a19c18a538dc7ef291c5a1"},
+ {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:afa17f5bc4d1b10afd4466fd3a44dc0e245382deca5b3c353d8b757f9e3ecb8d"},
+ {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dbad0e9d368bb989f4515da330b88a057617d16b6a8245084f1b05400f24609f"},
+ {file = "PyYAML-6.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:432557aa2c09802be39460360ddffd48156e30721f5e8d917f01d31694216782"},
+ {file = "PyYAML-6.0-cp311-cp311-win32.whl", hash = "sha256:bfaef573a63ba8923503d27530362590ff4f576c626d86a9fed95822a8255fd7"},
+ {file = "PyYAML-6.0-cp311-cp311-win_amd64.whl", hash = "sha256:01b45c0191e6d66c470b6cf1b9531a771a83c1c4208272ead47a3ae4f2f603bf"},
{file = "PyYAML-6.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:897b80890765f037df3403d22bab41627ca8811ae55e9a722fd0392850ec4d86"},
{file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50602afada6d6cbfad699b0c7bb50d5ccffa7e46a3d738092afddc1f9758427f"},
{file = "PyYAML-6.0-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:48c346915c114f5fdb3ead70312bd042a953a8ce5c7106d5bfb1a5254e47da92"},
@@ -420,10 +703,30 @@ pyyaml-env-tag = [
{file = "pyyaml_env_tag-0.1-py3-none-any.whl", hash = "sha256:af31106dec8a4d68c60207c1886031cbf839b68aa7abccdb19868200532c2069"},
{file = "pyyaml_env_tag-0.1.tar.gz", hash = "sha256:70092675bda14fdec33b31ba77e7543de9ddc88f2e5b99160396572d11525bdb"},
]
+requests = [
+ {file = "requests-2.28.1-py3-none-any.whl", hash = "sha256:8fefa2a1a1365bf5520aac41836fbee479da67864514bdb821f31ce07ce65349"},
+ {file = "requests-2.28.1.tar.gz", hash = "sha256:7c5599b102feddaa661c826c56ab4fee28bfd17f5abca1ebbe3e7f19d7c97983"},
+]
six = [
{file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
{file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},
]
+termcolor = [
+ {file = "termcolor-2.1.0-py3-none-any.whl", hash = "sha256:91dd04fdf661b89d7169cefd35f609b19ca931eb033687eaa647cef1ff177c49"},
+ {file = "termcolor-2.1.0.tar.gz", hash = "sha256:b80df54667ce4f48c03fe35df194f052dc27a541ebbf2544e4d6b47b5d6949c4"},
+]
+tomli = [
+ {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"},
+ {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"},
+]
+typing-extensions = [
+ {file = "typing_extensions-4.4.0-py3-none-any.whl", hash = "sha256:16fa4864408f655d35ec496218b85f79b3437c829e93320c7c9215ccfd92489e"},
+ {file = "typing_extensions-4.4.0.tar.gz", hash = "sha256:1511434bb92bf8dd198c12b1cc812e800d4181cfcb867674e0f8279cc93087aa"},
+]
+urllib3 = [
+ {file = "urllib3-1.26.13-py2.py3-none-any.whl", hash = "sha256:47cc05d99aaa09c9e72ed5809b60e7ba354e64b59c9c173ac3018642d8bb41fc"},
+ {file = "urllib3-1.26.13.tar.gz", hash = "sha256:c083dd0dce68dbfbe1129d5271cb90f9447dea7d52097c6e0126120c521ddea8"},
+]
verspec = [
{file = "verspec-0.1.0-py3-none-any.whl", hash = "sha256:741877d5633cc9464c45a469ae2a31e801e6dbbaa85b9675d481cda100f11c31"},
{file = "verspec-0.1.0.tar.gz", hash = "sha256:c4504ca697b2056cdb4bfa7121461f5a0e81809255b41c03dda4ba823637c01e"},
diff --git a/pyproject.toml b/pyproject.toml
index 0c8fd76f99..6d334f110b 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -1,17 +1,28 @@
[tool.poetry]
-name = "jspsych"
+name = "docs"
version = "0"
description = ""
authors = []
[tool.poetry.dependencies]
python = "^3.8"
+diskcache = "^5.4.0"
+requests = "^2.28.1"
[tool.poetry.dev-dependencies]
mkdocs = "^1.3.0"
mkdocs-material = "^8.2.15"
mike = "^1.1.2"
+[tool.poetry.group.dev.dependencies]
+mkdocs-macros-plugin = "^0.7.0"
+jsonpath-ng = "^1.5.3"
+black = "^22.10.0"
+isort = "^5.10.1"
+
[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"
+
+[tool.isort]
+profile = "black"
\ No newline at end of file