diff --git a/.eslintrc.json b/.eslintrc.json index a3edd8f..c52c6b8 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -12,9 +12,11 @@ "eslint:recommended", "@typhonjs-fvtt/eslint-config-foundry.js/0.8.0", "plugin:jest/recommended", - "plugin:prettier/recommended" + "plugin:prettier/recommended", + "plugin:jsdoc/recommended", + "plugin:jsdoc/recommended-typescript-flavor" ], - "plugins": ["jest"], + "plugins": ["jest", "jsdoc"], "parserOptions": { "ecmaVersion": 2020, "extraFileExtensions": [".cjs", ".mjs"], @@ -23,7 +25,8 @@ // Defines / overrides a few more environment parameters not provided in the configs above. "env": { - "browser": true + "browser": true, + "es6": true }, // Prevents overwriting any built in globals particularly from `@typhonjs-fvtt/eslint-config-foundry.js`, but also diff --git a/.vscode/settings.json b/.vscode/settings.json index a710567..35b1240 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,4 +1,7 @@ { "editor.formatOnSave": true, - "editor.defaultFormatter": "rvest.vs-code-prettier-eslint" + "editor.defaultFormatter": "rvest.vs-code-prettier-eslint", + "[json]": { + "editor.defaultFormatter": "vscode.json-language-features" + } } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index eb4ddf9..dd6c9ef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,41 +1,51 @@ +## 2.0.0 (2024-01-29) + +##### New Features + +* Plugin is now system agnostic and allows any user to create templates for their favorite systems. + * Documentation in [SYSTEMS.md]('https://github.com/EddieDover/theater-of-the-mind/SYSTEMS.md') + +* Added support for Forge hosting ([3beb550d](https://github.com/EddieDover/theater-of-the-mind/commit/3beb550d62030cd96a04aae7f06d399cd914fbb1)) + + ## 1.4.7 (2023-10-17) ##### Bug Fixes -* now displays variant stats properly ([6e1c94b5]('https://github.com/EddieDover/theater-of-the-mind'/commit/6e1c94b549a1019d43b195759536f686f822e11c)) +* now displays variant stats properly ([6e1c94b5](https://github.com/EddieDover/theater-of-the-mind/commit/6e1c94b549a1019d43b195759536f686f822e11c)) ## 1.4.6 (2023-10-17) ##### Bug Fixes -* prevent party sheet closing when opening character sheet ([1f0df29c]('https://github.com/EddieDover/theater-of-the-mind'/commit/1f0df29ce5de6471333b3c50fc21a72a8aae82eb)) +* prevent party sheet closing when opening character sheet ([1f0df29c](https://github.com/EddieDover/theater-of-the-mind/commit/1f0df29ce5de6471333b3c50fc21a72a8aae82eb)) ## 1.4.5 (2023-10-17) ##### Chores -* rewrote template system ([60dbaad3]('https://github.com/EddieDover/theater-of-the-mind'/commit/60dbaad30482cfc1c1006bb28d360d15d796a29f)) -* rewrote actor show/hide functionality ([60dbaad3]('https://github.com/EddieDover/theater-of-the-mind'/commit/60dbaad30482cfc1c1006bb28d360d15d796a29f)) -* restyled dialogs ([60dbaad3]('https://github.com/EddieDover/theater-of-the-mind'/commit/60dbaad30482cfc1c1006bb28d360d15d796a29f)) +* rewrote template system ([60dbaad3](https://github.com/EddieDover/theater-of-the-mind/commit/60dbaad30482cfc1c1006bb28d360d15d796a29f)) +* rewrote actor show/hide functionality ([60dbaad3](https://github.com/EddieDover/theater-of-the-mind/commit/60dbaad30482cfc1c1006bb28d360d15d796a29f)) +* restyled dialogs ([60dbaad3](https://github.com/EddieDover/theater-of-the-mind/commit/60dbaad30482cfc1c1006bb28d360d15d796a29f)) ##### New Features -* added ability to click on characters and open sheet ([60dbaad3]('https://github.com/EddieDover/theater-of-the-mind'/commit/60dbaad30482cfc1c1006bb28d360d15d796a29f)) +* added ability to click on characters and open sheet ([60dbaad3](https://github.com/EddieDover/theater-of-the-mind/commit/60dbaad30482cfc1c1006bb28d360d15d796a29f)) ## 1.4.0 (2023-10-17) ##### New Features -* added ability to show either online characters or a curated list of any non-npc ([5e209a14]('https://github.com/EddieDover/theater-of-the-mind'/commit/5e209a140e2919710f7e1119dbfc3a0d7f82631e)) +* added ability to show either online characters or a curated list of any non-npc ([5e209a14](https://github.com/EddieDover/theater-of-the-mind/commit/5e209a140e2919710f7e1119dbfc3a0d7f82631e)) ## 1.3.0 (2023-10-15) ##### New Features -* changed **sounds** dependency from attack-roll-check-5e with midi-qol ([3ef24300]('https://github.com/EddieDover/theater-of-the-mind'/commit/3ef24300229b2365823791936000c11b28dd4561)) -* Added Dark Mode option toggle. ([91175ad4]('https://github.com/EddieDover/theater-of-the-mind'/commit/91175ad4a088c01ab937ded8be1cf61a5427e00a)) -* added better changelog system ([2b104a68]('https://github.com/EddieDover/theater-of-the-mind'/commit/2b104a68e4d2687fe3a4b0b25d7edb5166226ca9)) +* changed **sounds** dependency from attack-roll-check-5e with midi-qol ([3ef24300](https://github.com/EddieDover/theater-of-the-mind/commit/3ef24300229b2365823791936000c11b28dd4561)) +* Added Dark Mode option toggle. ([91175ad4](https://github.com/EddieDover/theater-of-the-mind/commit/91175ad4a088c01ab937ded8be1cf61a5427e00a)) +* added better changelog system ([2b104a68](https://github.com/EddieDover/theater-of-the-mind/commit/2b104a68e4d2687fe3a4b0b25d7edb5166226ca9)) ## 1.2.1 (2023-10-07) diff --git a/README.md b/README.md index ab4abb3..8e44196 100644 --- a/README.md +++ b/README.md @@ -4,15 +4,24 @@ [![Foundry Hub Endorsements](https://img.shields.io/endpoint?logoColor=white&url=https%3A%2F%2Fwww.foundryvtt-hub.com%2Fwp-json%2Fhubapi%2Fv1%2Fpackage%2Ftheater-of-the-mind%2Fshield%2Fendorsements)](https://www.foundryvtt-hub.com/package/theater-of-the-mind/) [![Foundry Hub Comments](https://img.shields.io/endpoint?logoColor=white&url=https%3A%2F%2Fwww.foundryvtt-hub.com%2Fwp-json%2Fhubapi%2Fv1%2Fpackage%2Ftheater-of-the-mind%2Fshield%2Fcomments)](https://www.foundryvtt-hub.com/package/theater-of-the-mind/) +This module provides a GM with a table of characters, online only, or all, configurable in settings, in order to quickly see important stats, traits, abilites, etc. of all characters. Originally 5e only, it is now system agnostic and you can create easy to make .json templates for your system. It supports native Foundry and The Forge. Complete instructions for creating templates and placing them in the right folder on Foundry and Forge are included in the [SYSTEMS.MD] file. -The original intent of this module was to provide a 'party view' feature that I found missing when I first started using [FoundryVTT](https://www.foundryvtt.com) instead of [Fantasy Grounds](https://www.fantasygrounds.com). It will be updated with features that I personally want or need, or are requested of me by some poor soul. +The original intent of this module was to provide a 'party view' feature that I found missing when I first started using [FoundryVTT](https://www.foundryvtt.com) instead of [Fantasy Grounds](https://www.fantasygrounds.com). It will be updated with features that I personally want or need, or are requested of me by some poor soul. Several templates for various systems have been created, and more are already in the works with even more planned. + +If you create a template, please submit it via email, Discord or GitHub as a Pull Request, and we will include it in future updates with full credit. ## Features - Adds a 'Party Sheet' similar to that provided by Fantasy Grounds. Just click the Party Sheet icon on the Tokens Controls sub-menu. - - The Party Sheet can be configured via the options to either display only currently connected players, or all non-npc characters. When using the all-characters display, there is a separate dialog to allow hiding of any characters the DM doesn't need to worry about. + - The Party Sheet can be configured via the options to either display only currently connected players, or all non-npc characters. When using the all-characters display, there is a separate dialog to allow hiding of any characters the DM doesn't need to worry about. See the [SYSTEMS.md](SYSTEMS.md) file for instructions on how to create a json file for your own system. + - Clicking a character portrait will open their sheet. + - The Party Sheet is no longer bound to simply the built-in dnd5e system. Additional systems can be supported by writing a JSON file following the guidelines in [SYSTEMS.md](SYSTEMS.md) and placing it in either: + + - Native Foundry: your folder. + - The Forge: the folder named [totm] at the top level of your assets library (created by the module). + - Sound effects support if you have Syrinscape ([fvtt-syrin-control](https://github.com/frondeus/fvtt-syrin-control)) and Midi QOL ([midi-qol](https://gitlab.com/tposney/midi-qol/)) installed. # Support @@ -35,3 +44,21 @@ Specific Characters ![Preview of Plugin Party Sheet - Specific Actors](images/preview2.png) +# Supported Systems + +Built in (by Eddie Dover): + - DnD5e "dnd5e" - Note: this does not require any upload of a .json, but you can make your own or edit the example in the [example_templates] folder to your liking and it will show up in the dropdown of available .json files + +Templates by Michael Card (Emo Cthulhu): + - Alien RPG "alienrpg" + - Blade Runner RPG "blade-runner" + - Dragonbane "dragonbane" + - Starfinder "sfrpg" + - The Walking Dead Universe RPG "twdu" + - Vaesen "vaesen" + + - In Progress: Coriolis "yzecoriolis", Fallout 2d20 "fallout", Cyberpunk RED "cyberpunk-red-core" + + - Planned: Pathfinder 1e, Pathfinder 2e + +Please see the [SYSTEMS.md](SYSTEMS.md) file for how to use the provided templates and install them in the correct directory. Theater of the Mind supports Forge installations, and information in these documents will let you know what you have to do differently on native Foundry and The Forge. diff --git a/SYSTEMS.md b/SYSTEMS.md new file mode 100644 index 0000000..cfcd743 --- /dev/null +++ b/SYSTEMS.md @@ -0,0 +1,422 @@ +# Template System JSON Documentation + +Examples can be found in the [example_templates](https://github.com/EddieDover/Theater-of-the-Mind/example_templates) folder. As well, several systems other than 5e have been made, and are in the [example_templates] folder in native Foundry. If using the Forge, install the module on your local Foundry installation to have access to the [example_templates] folder, and to upload any you would like to use to your Assets Library in the folder at the top level. Or, if you haven't installed Foundry and only used the license key on The Forge, use the GitHub link above. In this case, you will have to download the file to your computer, then upload it to The Forge. If you create a template, please submit it via email, Discord or GitHub, and we will include it in future updates with full credit. + +If using native Foundry, place your templates in the folder. + +If using The Forge, this module will create a folder at the top level of your Assets Library named `totm`. Place your templates in this folder. + +## Required Minimal Top Level Structure + +```json +{ + "name": "", + "system": "", + "author": "", + "rows": [] // See Below Section For Details +} +``` + +**Note: Templates will be displayed to the user as 'YOUR_TEMPLATE_NAME - YOUR_NAME' and only if the system matches the current system in use.** + +### Optional Top Level Properties + +The following properties are also available at the top level of the system structure. + + **offline_excludes_property** - string - This is optional and defaults to the value of `actor.type`. Only override if needed. All overrides are treated as if their parent object is the character. Example: + ```json + { + "name": "", + "system": "", + "author": "", + "offline_excludes_property": "system.subtype", + "offline_excludes": [ + "npc" + ], + "rows": [] // See Below Section For Details + } + ``` + + **offline_excludes** - array - This is optional and defaults to `["npc"]`. Any object inside the exclusion list that matches the value of the offline_excludes_property will be excluded from showing in the party list. Example: + ```json + { + "name": "", + "system": "", + "author": "", + "offline_excludes": [ + "npc", + "vehicle", + "creature", + "base", + "starship" + ], + "rows": [] // See Below Section For Details + } + ``` + + **offline_includes_property** - string - This is optional but required both it and **offline_includes** are required to work, if used. It has no default property. It will be treated as if its parent object is the character. If you use this, **offline_excludes_property**/**offline_excludes** will be ignored. Example: + ```json + { + "name": "", + "system": "", + "author": "", + "offline_includes_property": "system.subtype", + "offline_includes": [ + "pc" + ], + "rows": [] // See Below Section For Details + } + ``` + + **offline_includes**: array - This is the same as **offline_excludes** but it is an inclusion list. + +### Row Specific Structure + +The "rows" property must contain an array of an array of column data. + +``` "rows": [] ``` is empty + +``` "rows": [ [] ] ``` will contain one row + +``` "rows": "[ [], [] ]``` will contain two rows. + +Inside the row array, the plugin expects items in the following format: +```json +{ + "name": "", + "type": "", + "header": "", + "value": "" +} +``` + +Therefore, a one row array should look like: +```json + "rows": [ + [ + { + + }, + { + + } + ] +] +``` + +Two rows should look like: +```json + "rows": [ + [ + { + + }, + { + + } + ], + [ + { + + }, + { + + } + ] +] +``` + +You can have more than two rows. + +__Each item corresponds to a single column on the sheet. If you have multiple rows, then each row must have the same number of columns.__ See the below Examples section for more examples (and note, in the above structure example, the two row example has 2 columns in each). In order to achieve this, you may have to make empty columns: +```json + { + "name": ".", + "type": "direct", + "header": "hide", + "text:" "" + }, // no comma if the last column +``` +Note that even empty columns need unique names. Feel free to be as descriptive as necessary, since the column **name** will not be displayed if the `header` is not `show`. **No two columns can have the same `name` value.** + +### Primary Property Specifics + +**name** - This can be any value you wish. If the header is "show" then it will be displayed as the column header. + +**type** - This is the type of data being displayed, possible choices are: + * **direct** - This will process the text in the **value** property and parse out any string sections to see if they are properties of the character. + * **direct-complex** - This will expect the **value** property to contain an array of complex types. See documentation below. + * **string** - This will simply display the text in the **value** property without modification. + * **array-string-builder** - This will accept a **value** property in the following format: ** => ** See examples below for more information + * **charactersheet** - This will display the character sheet in the column, ignoring anything in the **value** property. + +**header** - This property controls if the column text is displayed as a header in the generated table. It accepts either 'show' or 'skip'. + * **show** - Show the column as a **header** column. + * **skip** - Do NOT Show the column as a **header** column. + +**maxwidth** - This _optional_ property controls the maximum width of the column. Value must be a number that represents the width in pixels. `"maxwidth": 200,` (note the lack of quotes around the number) + +**minwidth** - This _optional_ property controls the minimum width of the column. Value must be a number that represents the width in pixels. `"minwidth": 100,` + +**valign** - This _optional_ property controls the vertical alignment of the cells. It only accepts 'top' and 'bottom'. If left out, or if an improper value is used, the setting will be ignored and will use whatever css the game system provides, since as some systems already override the table css and set the whole table to top, or middle. However, if your system has css code to set valign on table properties, using valign should override the system's value. + +**text** - This property is either a **string**, **boolean**, or an **array** of objects based on if you're using **direct-complex** or not. See examples below. + +### Text - accepted values + * boolean - Quotes are not needed, simply use `false`, or `true`, i.e. `"match": true,` + * numbers - Always examine your systems values to see if they are strings or plain numbers, if they are plain numbers do not include quotes around the value, i.e. `"match": 23,` If they are actually strings, then you will need to surround the number with quotes to make it a string as well, i.e. `"match:" "23",` + * string: You can include arbitrary text in your output values. Simply make sure they are within the quotes for the text you are creating, i.e. `"text": "name has system.criticalInjury.time days left before system.criticalInjury.name heals.` + * Due to the way things are parsed by the plugin there are a few very important caveats you must keep in mind: + 1. If you are using a data string like "system.attributes.str", or a keyword (see below) like `{newline}`, along with custom text, such as `STR: system.attributes.str` as an output, there **must** be spaces around the data string, + - INCORRECT - `STR:system.attributes.str/system.attributes.maxstr` + - CORRECT - `STR: system.attributes.str / system.attributes.maxstr` + * The more astute among you may notice that in the example templates, `.value` is often left out. To save your poor typing muscles, even if the value you find for a piece of character data is `system.attributes.str.value` the module parses data in the following way. Entering `system.attributes.str` will make the module look for `system.attributes.str.value` and display that if it finds it. If not found, it will display `system.attributes.str` as is. + +### Text - Special Keywords + +There are a few special keywords that must be surrounded by { } marks, to allow easier formatting, note that they must be surrounded by spaces unless they are next to the opening or closing quotes. They are as follows: + + * {newline} - Adds a line break to the text rendered. + * {charactersheet} - Inserts a clickable image of the character that will open their character sheet. + * {+} - Adds the values of two objects and outputs the result, i.e. `system.attributes.str {+} system.attributes.wis` will output the character's str and wis added together. + +### Direct-Complex Object + +The direct complex object was originally created to show values for attributes but only if they existed. It was originally used for the DND5E Senses display. + +A direct complex object has three properties: +* type - The type of object. Currently accepted values are: + - "exists" - Does the **value** exist or not. If using **exists** it will look for an _OPTIONAL_ property named **else** and if the thing you're checking for doesn't exist, the value of **else** will be parsed. You may leave **else** out if not using it. + ```json + { + "type": "exists", + "value": "system.attribute.isplayersick", + "text": "Player is sick with system.attribute.sickness", + "else": "Healthy for system.attribute.daysSinceSick days" + }, + ``` + - "match" - Checks for an additional **match** property. If the **value** matches the **match** property, then **text** is processed. + - "match-all" - Same as match, but the **value** can be an array of properties to match against. +* value - The attribute that you're checking against +* text - The text to be displayed if the **type** check passes. It will be processed in the same manner as the **value** is processed on a standard **direct** column type. + +```json +{ + "name": "Senses", + "type": "direct-complex", + "header": "hide", + "value": [ + { + "type": "exists", + "value": "system.attributes.senses.darkvision", + "text": "Darkvision: system.attributes.senses.darkvision" + }, + { + "type": "exists", + "value": "system.attributes.senses.blindsight", + "text": "Blindsight: system.attributes.senses.blindsight" + }, + { + "type": "exists", + "value": "system.attributes.senses.tremorsense", + "text": "Tremorsense: system.attributes.senses.tremorsense" + }, + { + "type": "exists", + "value": "system.attributes.senses.truesight", + "text": "Truesight: system.attributes.senses.truesight" + }, + { + "type": "exists", + "value": "system.attributes.senses.special", + "text": "Special: system.attributes.senses.special" + } + ] +} +``` + +In this example, the table will contain one column named Senses, but the column name will be hidden (skipped). It will then loop through each item in the **value** field. In this case, it will check each of the dnd5e system senses. If they exist on the character, then the text will be displayed, formatted as a **direct** line, and all appended together at the end. ***Note*** All values that exist will be displayed. You can additionally follow the **text** with **else**, and if the contents of **value** DO NOT exist the value in **else** will be displayed instead. + +In this example, the following character only has one sense that exists, so it's the only one displayed: + +![Example Sense](doc_images/senses1.png) + + +Here's an example of how to use **match**: +```json + { + "name": "Career", + "align": "center", + "type": "direct-complex", + "header": "hide", + "text": [ + { + "type": "match", + "ifdata": "system.general.career", + "matches": "1", + "text": "Colonial Marine" + }, + { + "type": "match", + "ifdata": "system.general.career", + "matches": "2", + "text": "Career: Colonial Marshall" + }, + { + "type": "match", + "ifdata": "system.general.career", + "matches": "3", + "text": "Career: Company Agent" + }, + { + "type": "match", + "ifdata": "system.general.career", + "matchse": "8", + "text": "Pilot" + } + ] + }, +``` +In this example, the system will contain a column named Career, but the column name will be hidden. It will then loop through each item in the **text** field. In this system `Alien RPG`, the player's career is a number, stored in `system.general.career`. In this example, if the value in `system.general.career` matches `1` then the text `Colonial Marine` is output, otherwise, if the career matches `2` then the text is `Colonial Marshall`, if `3`, `Company Agent` is output and so on. All values that match will be displayed. Any items where **matches** is the same as the contents of **ifdata** will display the value in **text**. You can additionally follow the **text** with **else**, and if the contents of **ifdata** DO NOT match the value in **matches** the value in **else** will be displayed instead. + + +## Examples + +### Extremely Basic File Example +Code: +```json +{ + "name": "Test Person's DND 5E Template", + "system": "dnd5e", + "author": "Test Person", + "rows" : [ + [ + { + "name": "Name", + "type": "direct", + "header": "show", + "text": "{charactersheet} name {newline} system.details.race" + } + ] + ] +} + +// Note that this uses both the charactersheet and newline special keywords. +``` +Result: + +![Basic Example](doc_images/ex1.png) + +## **Notes for Forge Users:** + * It is best to use native Foundry for testing until you are 100% certain you are happy with your template. + * Between The Forge's upload system that will not upload a file again if it sees the file already exists, and various browsers caching files, you may find that if you upload a changed .json, the changes will not appear. This is why testing is best on Foundry where you can just save the file, then refresh your client (F5), and changes should be instantaneous. If you can only use Forge then It is highly recommended that multiple edited uploads be a different file name every time, to avoid this issue, until your template is complete. + * The Forge does not allow read or write access to text based files in the Core Data systems or modules, only images which are read-only. Thus to grab the example .json files use the methods described at the top of this document. + +## **Notes for inexperienced template creators:** + + * A JSON friendly editor like VSCode, Notepad++, etc., is highly suggested. They show you with instant feedback if you put or forget a comma where you shouldn't, etc. VSCode is particularly nice and it creates a list of things you type very often, and gives you a box to autocomplete your entries. + * Many problems are simply with your JSON file. A missed comma there, a comma that shouldn't exist here. + * If your template fails to appear, then press F12 and check your console logs for errors. The module tries to let you know if there are issues with your JSON, it will be early on in the console, you'll see a list of JSONs loaded, and if they are valid, it will say Loaded vaesen.json - good json. + * Use JSON Validation extensions for your editor of choice, or sites like https://jsonlint.com/ to validate your JSON. + * Double check that property values you're using are correct for your selected system. + * The first great way to do this, is to click the debugger for the module on. Then when the party sheet is rendered, you can go into the console and you will see a list of Actors. Clicking the side arrow down will show the name so you can narrow down whichever actor/actors are acting up. Opening the entire entry will show all the values for that Actor. + * Another way is to install Illandril's Token Tooltips. Place some actors on the scene, off to the left side. Then go in to Configure Settings > Illandril's Token Tooltips > Configure Tooltip Values. At the bottom left is a button that says "Enable Data Key Debugger." Once clicked you can hover over a token, and all the values in that token will be displayed. You can ignore all the ones about prototype.token, and look for system.attributes.whatever/system.abilities.whatever, etc. + * At the very bottom is type, and you only want to show PC's, so check to see if type is character. You may want to drag some tokens like vehicles, animals and monsters onto the scene so you can see what their type is listed as, and exclude that type using the offline_excludes array detailed above. + +## **Other Notes:** + + * Module Conflicts: + - Arius Planeswalker's Stylish Journal for Monk's Enhanced Journal - changes the CSS so dramatically that tables will not render correctly. + - Possible issues with Token Attacher tokens - in testing some MAD Cartographer maps caused the tokens that come with the map modules would show up in the Party Sheet, despite having proper excludes in the header of the .json. It is not an issue with MAD Cartographer maps or their dependencies, it seems to be another module that causes these Actors not to import properly. As soon as the offending module is found it will be listed here. + * CSS: + - Some system developers are bound and determined to change everything about default Foundry css just because they can (I'm looking at you, Free League Publishing), so while every effort has been made to make the tables look the same between systems, you may see some that are quite different (I'm looking at you, Vaesen). + - That said, the module can only accommodate some minimal alignment and visual improvements. To try and override every system out there would be impossible. There is no intention to allow more than minwidth/maxwidth, align and valign. + +## **Still not sure where to start? _Look no further!_** + * First jot down the values you think you want to display from one of your character's character sheets. + * Decide if you want one row, or need 2 because you have a lot of information to display. Or do both! + * Choose one of the following .json examples, and make sure you have the name you want displayed, the exact name of your system, and your name added. + * Open your editor of choice and paste the example into it. You've created your first template! + * Save it in the proper [totm] folder as described at the top of this document. + * Enable the module, and refresh. + * In the module settings, turn on the debugger and turn off show only online players. + * Now, when you click the Party Sheet icon in your token controls, you will get a thin table with the characters in the system and their clickable Actor Portraits, and their name. + * Open the console, and scroll for the listings that say "SystemActor" beneath a line that says "These are all the actors in your game. They have not yet been filtered based on your inclusions/exclusions." It has a header "TOTM DEBUG CHARACTER LIST." Click the arrow to open an Actor, then click the arrow to open system. Most of your values will be here. Some good detective work will help you find the values you want. Remember that you will have to assemble them, starting with system, then, for instance, attributes, then the name of the attribute, ending up with "system.attribute.str" as a typical example. + * Start adding them to further columns, and you'll be done in no time if you've read these instructions thoroughly. + +One row: + +```json +{ + "name": "Some System - 1 Row", + "system": "some-system", + "author": "Your Name Here", + "offline_excludes": [ + "npc", + "base" + ], + "rows": [ + [ + { + "name": "Character Sheet", + "type": "charactersheet", + "align": "center", + "header": "hide", + "text": "" + }, + { + "name": "Name", + "type": "direct", + "align": "center", + "header": "show", + "text": "name" + } + ] + ] +} +``` + +Two Rows: +```json +{ + "name": "Some System - Two Rows", + "system": "some-system", + "author": "Your Name Here", + "offline_excludes": [ + "npc", + "base" + ], + "rows": [ + [ + { + "name": "Character Sheet", + "type": "charactersheet", + "align": "center", + "header": "hide", + "text": "" + }, + { + "name": "Name", + "type": "direct", + "align": "center", + "header": "show", + "text": "name" + } + ], + [ + { + "name": ".", + "type": "direct", + "header": "hide", + "text": "" + }, + { + "name": "..", + "type": "direct", + "header": "hide", + "text": "" + } + ] + ] +} +``` diff --git a/doc_images/ex1.png b/doc_images/ex1.png new file mode 100644 index 0000000..b906bcf Binary files /dev/null and b/doc_images/ex1.png differ diff --git a/doc_images/senses1.png b/doc_images/senses1.png new file mode 100644 index 0000000..e9a582a Binary files /dev/null and b/doc_images/senses1.png differ diff --git a/example_templates/alienrpg.json b/example_templates/alienrpg.json new file mode 100644 index 0000000..bbdd8b3 --- /dev/null +++ b/example_templates/alienrpg.json @@ -0,0 +1,196 @@ +{ + "name": "Alien: The Roleplaying Game", + "system": "alienrpg", + "author": "Michael Card (Emo Cthulhu)", + "offline_includes_property": "system.header.npc", + "offline_includes": [ + false + ], + "rows": [ + [ + { + "Name": "Character", + "type": "charactersheet", + "header": "hide", + "text": "" + }, + { + "name": "Name", + "type": "direct", + "maxwidth": 100, + "align": "left", + "header": "show", + "text": "name" + }, + { + "name": "Career", + "align": "left", + "type": "direct-complex", + "header": "show", + "text": [ + { + "type": "match", + "ifdata": "system.general.career", + "matches": "1", + "text": "Career: Colonial Marine" + }, + { + "type": "match", + "ifdata": "system.general.career", + "matches": "2", + "text": "Career: Colonial Marshall" + }, + { + "type": "match", + "ifdata": "system.general.career", + "matches": "3", + "text": "Career: Company Agent" + }, + { + "type": "match", + "ifdata": "system.general.career", + "matches": "4", + "text": "Career: Kid" + }, + { + "type": "match", + "ifdata": "system.general.career", + "matches": "5", + "text": "Career: Medic" + }, + { + "type": "match", + "ifdata": "system.general.career", + "matches": "6", + "text": "Career: Mercenary" + }, + { + "type": "match", + "ifdata": "system.general.career", + "matches": "7", + "text": "Career: Officer" + }, + { + "type": "match", + "ifdata": "system.general.career", + "matches": "8", + "text": "Career: Pilot" + }, + { + "type": "match", + "ifdata": "system.general.career", + "matches": "9", + "text": "Career: Roughneck" + }, + { + "type": "match", + "ifdata": "system.general.career", + "matches": "10", + "text": "Career: Scientist" + }, + { + "type": "match", + "ifdata": "system.general.career", + "matches": "11", + "text": "Synthetic" + }, + { + "type": "match", + "ifdata": "system.general.career", + "matches": "12", + "text": "Homebrew" + } + ] + }, + { + "name": "Health", + "minwidth": 50, + "type": "direct", + "align": "center", + "valign": "top", + "header": "show", + "text": "system.header.health / system.header.health.max" + }, + { + "name": "Stress", + "minwidth": 50, + "type": "direct-complex", + "align": "center", + "valign": "top", + "header": "show", + "text": [ + { + "type": "match", + "ifdata": "type", + "matches": "synthetic", + "text": "N/A" + }, + { + "type": "match", + "ifdata": "type", + "matches": "character", + "text": "system.header.stress" + } + ] + }, + { + "name": "Panic", + "minwidth": 50, + "type": "direct-complex", + "align": "center", + "valign": "top", + "header": "show", + "text": [ + { + "type": "match", + "ifdata": "type", + "matches": "synthetic", + "text": "N/A" + }, + { + "type": "match", + "ifdata": "type", + "matches": "character", + "text": "system.general.panic.lastRoll" + } + ] + }, + { + "name": "Strength Group", + "maxwidth": 70, + "type": "direct", + "align": "left", + "valign": "top", + "header": "show", + "text": "STR: system.attributes.str {newline} {newline} CC: system.skills.closeCbt / system.skills.closeCbt {+} system.attributes.str {newline} HM: system.skills.heavyMach / system.skills.heavyMach {+} system.attributes.str {newline} Sta: system.skills.stamina / system.skills.stamina {+} system.attributes.str" + }, + { + "name": "Agility Group", + "maxwidth": 70, + "type": "direct", + "align": "left", + "valign": "top", + "header": "show", + "text": "AGL: system.attributes.agl {newline} {newline} RC: system.skills.rangedCbt / system.skills.rangedCbt {+} system.attributes.agl {newline} Mob: system.skills.mobility / system.skills.mobility {+} system.attributes.agl {newline} Pilot: system.skills.piloting / system.skills.piloting {+} system.attributes.agl" + }, + { + "name": "Empathy Group", + "maxwidth": 70, + "type": "direct", + "align": "left", + "valign": "top", + "header": "show", + "text": "EMP: system.attributes.emp {newline} {newline} Com: system.skills.command / system.skills.command {+} system.attributes.emp {newline} Man: system.skills.manipulation / system.skills.manipulation {+} system.attributes.emp {newline} Med: system.skills.medicalAid / system.skills.medicalAid {+} system.attributes.emp" + }, + { + "name": "Wits Group", + "maxwidth": 70, + "type": "direct", + "align": "left", + "valign": "top", + "header": "show", + "text": "WIT: system.attributes.wit {newline} {newline} Obs: system.skills.observation / system.skills.observation {+} system.attributes.wit {newline} Sur: system.skills.survival / system.skills.survival {+} system.attributes.wit {newline} CT: system.skills.comtech / system.skills.comtech {+} system.attributes.wit" + } + ] + ] +} \ No newline at end of file diff --git a/example_templates/blade-runner-basic.json b/example_templates/blade-runner-basic.json new file mode 100644 index 0000000..b8416ce --- /dev/null +++ b/example_templates/blade-runner-basic.json @@ -0,0 +1,96 @@ +{ + "name": "Blade Runner: The Roleplaying Game - Basic", + "system": "blade-runner", + "author": "Michael Card (Emo Cthulhu)", + "offline_includes_property": "system.subtype", + "offline_includes": [ + "pc" + ], + "rows": [ + [ + { + "name": "xx", + "type": "charactersheet", + "header": "hide", + "text": "" + }, + { + "name": "Name - Archetype - Nature", + "maxwidth": 100, + "type": "direct", + "align": "left", + "header": "show", + "text": "name {newline} Archetype: system.archetype {newline} Nature: system.nature" + }, + { + "name": "Health & Resolve", + "maxwidth": 70, + "type": "direct", + "align": "center", + "valign": "top", + "header": "show", + "text": "H: system.health.value / system.health.max {newline} R: system.resolve.value / system.resolve.max" + }, + { + "name": "STR Group", + "minwidth": 115, + "type": "direct", + "align": "left", + "valign": "top", + "header": "show", + "text": "STR: d system.attributes.str {newline} {newline} HtH: d system.skills.closeCombat / d system.skills.closeCombat + d system.attributes.str {newline} For: d system.skills.force / d system.skills.force + d system.attributes.str {newline} Stam: d system.skills.stamina / d system.skills.stamina + d system.attributes.str" + }, + { + "name": "AGL Group", + "minwidth": 115, + "type": "direct", + "align": "left", + "valign": "top", + "header": "show", + "text": "AGL: d system.attributes.agi {newline} {newline} Fire: d system.skills.firearms / d system.skills.firearms.value + d system.attributes.agi {newline} Mob: d system.skills.mobility / d system.skills.mobility + d system.attributes.agi {newline} Stea: d system.skills.stealth / d system.skills.stealth + d system.attributes.agi" + }, + { + "name": "INT Group", + "minwidth": 115, + "type": "direct", + "align": "left", + "valign": "top", + "header": "show", + "text": "INT: d system.attributes.int {newline} {newline} Med: d system.skills.medicalAid / d system.skills.medicalAid.value + d system.attributes.int {newline} Obs: d system.skills.observation / d system.skills.observation + d system.attributes.int {newline} Tech: d system.skills.tech / d system.skills.tech + d system.attributes.int {newline} {newline} Driving*: d system.skills.driving" + }, + { + "name": "EMP Group", + "minwidth": 115, + "type": "direct", + "align": "left", + "valign": "top", + "header": "show", + "text": "EMP: d system.attributes.emp {newline} {newline} Con: d system.skills.connections / d system.skills.connections.value + d system.attributes.emp.value {newline} Ins: d system.skills.insight / d system.skills.insight + d system.attributes.emp {newline} Man: d system.skills.manipulation / d system.skills.manipulation + d system.attributes.emp" + }, + { + "name": "Chin", + "type": "direct", + "align": "center", + "valign": "top", + "header": "show", + "text": "system.metaCurrencies.chinyen" + }, + { + "name": "Hum", + "type": "direct", + "align": "center", + "valign": "top", + "header": "show", + "text": "system.metaCurrencies.humanity" + }, + { + "name": "Promo", + "type": "direct", + "align": "center", + "valign": "top", + "header": "show", + "text": "system.metaCurrencies.promotion" + } + ] + ] +} \ No newline at end of file diff --git a/example_templates/blade-runner-expanded.json b/example_templates/blade-runner-expanded.json new file mode 100644 index 0000000..1f661de --- /dev/null +++ b/example_templates/blade-runner-expanded.json @@ -0,0 +1,1120 @@ +{ + "name": "Blade Runner: The Roleplaying Game - Expanded", + "system": "blade-runner", + "author": "Michael Card (Emo Cthulhu)", + "offline_includes_property": "system.subtype", + "offline_includes": [ + "pc" + ], + "rows": [ + [ + { + "name": "xx", + "type": "charactersheet", + "header": "hide", + "text": "" + }, + { + "name": "Name - Archetype - Nature", + "maxwidth": 100, + "type": "direct", + "align": "left", + "header": "show", + "text": "name {newline} Archetype: system.archetype {newline} Nature: system.nature" + }, + { + "name": "Health & Resolve", + "maxwidth": 70, + "type": "direct", + "align": "center", + "valign": "top", + "header": "show", + "text": "H: system.health.value / system.health.max {newline} R: system.resolve.value / system.resolve.max" + }, + { + "name": "STR Group", + "type": "direct-complex", + "minwidth": 80, + "align": "left", + "valign": "top", + "header": "show", + "text": [ + { + "type": "match", + "ifdata": "system.attributes.str", + "matches": 0, + "text": "STR: -- {newline} {newline}" + }, + { + "type": "match", + "ifdata": "system.attributes.str", + "matches": "0", + "text": "STR: -- {newline} {newline}" + }, + { + "type": "match", + "ifdata": "system.attributes.str", + "matches": 6, + "text": "STR: D (d6) {newline} {newline}" + }, + { + "type": "match", + "ifdata": "system.attributes.str", + "matches": "6", + "text": "STR: D (d6) {newline} {newline}" + }, + { + "type": "match", + "ifdata": "system.attributes.str", + "matches": 8, + "text": "STR: C (d8) {newline} {newline}" + }, + { + "type": "match", + "ifdata": "system.attributes.str", + "matches": "8", + "text": "STR: C (d8) {newline} {newline}" + }, + { + "type": "match", + "ifdata": "system.attributes.str", + "matches": 10, + "text": "STR: B (d10) {newline} {newline}" + }, + { + "type": "match", + "ifdata": "system.attributes.str", + "matches": "10", + "text": "STR: B (d10) {newline} {newline}" + }, + { + "type": "match", + "ifdata": "system.attributes.str", + "matches": 12, + "text": "STR: A (d12) {newline} {newline}" + }, + { + "type": "match", + "ifdata": "system.attributes.str", + "matches": "12", + "text": "STR: A (d12) {newline} {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.closeCombat", + "matches": "0", + "text": "H2H: -- {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.closeCombat", + "matches": 0, + "text": "H2H: -- {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.closeCombat", + "matches": 6, + "text": "H2H: D (d6) {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.closeCombat", + "matches": "6", + "text": "H2H: D (d6) {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.closeCombat", + "matches": 8, + "text": "H2H: C (d8) {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.closeCombat", + "matches": "8", + "text": "H2H: C (d8) {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.closeCombat", + "matches": 10, + "text": "H2H: B (d10) {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.closeCombat", + "matches": "10", + "text": "H2H: B (d10) {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.closeCombat", + "matches": 12, + "text": "H2H: A (d12) {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.closeCombat", + "matches": "12", + "text": "H2H: A (d12) {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.force", + "matches": "0", + "text": "Force: -- {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.force", + "matches": 0, + "text": "Force: -- {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.force", + "matches": 6, + "text": "Force: D (d6) {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.force", + "matches": "6", + "text": "Force: D (d6) {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.force", + "matches": 8, + "text": "Force: C (d8) {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.force", + "matches": "8", + "text": "Force: C (d8) {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.force", + "matches": 10, + "text": "Force: B (d10) {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.force", + "matches": "10", + "text": "Force: B (d10) {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.force", + "matches": 12, + "text": "Force: A (d12) {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.force", + "matches": "12", + "text": "Force: A (d12) {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.stamina", + "matches": "0", + "text": "Stamina: --" + }, + { + "type": "match", + "ifdata": "system.skills.stamina", + "matches": 0, + "text": "Stamina: --" + }, + { + "type": "match", + "ifdata": "system.skills.stamina", + "matches": 6, + "text": "Stamina: D (d6)" + }, + { + "type": "match", + "ifdata": "system.skills.stamina", + "matches": "6", + "text": "Stamina: D (d6)" + }, + { + "type": "match", + "ifdata": "system.skills.stamina", + "matches": 8, + "text": "Stamina: C (d8)" + }, + { + "type": "match", + "ifdata": "system.skills.stamina", + "matches": "8", + "text": "Stamina: C (d8)" + }, + { + "type": "match", + "ifdata": "system.skills.stamina", + "matches": 10, + "text": "Stamina: B (d10)" + }, + { + "type": "match", + "ifdata": "system.skills.stamina", + "matches": "10", + "text": "Stamina: B (d10)" + }, + { + "type": "match", + "ifdata": "system.skills.stamina", + "matches": 12, + "text": "Stamina: A (d12)" + }, + { + "type": "match", + "ifdata": "system.skills.stamina", + "matches": "12", + "text": "Stamina : A (d12)" + } + ] + }, + { + "name": "AGI Group", + "type": "direct-complex", + "minwidth": 80, + "align": "left", + "valign": "top", + "header": "show", + "text": [ + { + "type": "match", + "ifdata": "system.attributes.agi", + "matches": 0, + "text": "AGI: -- {newline} {newline}" + }, + { + "type": "match", + "ifdata": "system.attributes.agi", + "matches": "0", + "text": "AGI: -- {newline} {newline}" + }, + { + "type": "match", + "ifdata": "system.attributes.agi", + "matches": 6, + "text": "AGI: D (d6) {newline} {newline}" + }, + { + "type": "match", + "ifdata": "system.attributes.agi", + "matches": "6", + "text": "AGI: D (d6) {newline} {newline}" + }, + { + "type": "match", + "ifdata": "system.attributes.agi", + "matches": 8, + "text": "AGI: C (d8) {newline} {newline}" + }, + { + "type": "match", + "ifdata": "system.attributes.agi", + "matches": "8", + "text": "AGI: C (d8) {newline} {newline}" + }, + { + "type": "match", + "ifdata": "system.attributes.agi", + "matches": 10, + "text": "AGI: B (d10) {newline} {newline}" + }, + { + "type": "match", + "ifdata": "system.attributes.agi", + "matches": "10", + "text": "AGI: B (d10) {newline} {newline}" + }, + { + "type": "match", + "ifdata": "system.attributes.agi", + "matches": 12, + "text": "AGI: A (d12) {newline} {newline}" + }, + { + "type": "match", + "ifdata": "system.attributes.agi", + "matches": "12", + "text": "AGI: A (d12) {newline} {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.firearms", + "matches": "0", + "text": "Firearms: -- {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.firearms", + "matches": 0, + "text": "Firearms: -- {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.firearms", + "matches": 6, + "text": "Firearms: D (d6) {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.firearms", + "matches": "6", + "text": "Firearms: D (d6) {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.firearms", + "matches": 8, + "text": "Firearms: C (d8) {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.firearms", + "matches": "8", + "text": "Firearms: C (d8) {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.firearms", + "matches": 10, + "text": "Firearms: B (d10) {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.firearms", + "matches": "10", + "text": "Firearms: B (d10) {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.firearms", + "matches": 12, + "text": "Firearms: A (d12) {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.firearms", + "matches": "12", + "text": "Firearms: A (d12) {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.mobility", + "matches": "0", + "text": "Mob: -- {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.mobility", + "matches": 0, + "text": "Mob: -- {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.mobility", + "matches": 6, + "text": "Force: D (d6) {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.mobility", + "matches": "6", + "text": "Mob: D (d6) {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.mobility", + "matches": 8, + "text": "Mob: C (d8) {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.mobility", + "matches": "8", + "text": "Mob: -- {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.mobility", + "matches": 10, + "text": "Mob: B (d10) {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.mobility", + "matches": "10", + "text": "Mob: B (d10) {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.mobility", + "matches": 12, + "text": "Mob: A (d12) {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.mobility", + "matches": "12", + "text": "Mob: A (d12) {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.stealth", + "matches": "0", + "text": "Stealth: --" + }, + { + "type": "match", + "ifdata": "system.skills.stealth", + "matches": 0, + "text": "Stealth: --" + }, + { + "type": "match", + "ifdata": "system.skills.stealth", + "matches": 6, + "text": "Stealth: D (d6)" + }, + { + "type": "match", + "ifdata": "system.skills.stealth", + "matches": "6", + "text": "Stealth: D (d6)" + }, + { + "type": "match", + "ifdata": "system.skills.stealth", + "matches": 8, + "text": "Stealth: C (d8)" + }, + { + "type": "match", + "ifdata": "system.skills.stealth", + "matches": "8", + "text": "Stealth: C (d8)" + }, + { + "type": "match", + "ifdata": "system.skills.stealth", + "matches": 10, + "text": "Stealth: B (d10)" + }, + { + "type": "match", + "ifdata": "system.skills.stealth", + "matches": "10", + "text": "Stealth: B (d10)" + }, + { + "type": "match", + "ifdata": "system.skills.stealth", + "matches": 12, + "text": "Stealth: A (d12)" + }, + { + "type": "match", + "ifdata": "system.skills.stealth", + "matches": "12", + "text": "Stealth : A (d12)" + } + ] + }, + { + "name": "INT Group", + "type": "direct-complex", + "minwidth": 80, + "align": "left", + "valign": "top", + "header": "show", + "text": [ + { + "type": "match", + "ifdata": "system.attributes.int", + "matches": 0, + "text": "INT: -- {newline} {newline}" + }, + { + "type": "match", + "ifdata": "system.attributes.int", + "matches": "0", + "text": "INT: -- {newline} {newline}" + }, + { + "type": "match", + "ifdata": "system.attributes.int", + "matches": 6, + "text": "INT: D (d6) {newline} {newline}" + }, + { + "type": "match", + "ifdata": "system.attributes.int", + "matches": "6", + "text": "INT: D (d6) {newline} {newline}" + }, + { + "type": "match", + "ifdata": "system.attributes.int", + "matches": 8, + "text": "INT: C (d8) {newline} {newline}" + }, + { + "type": "match", + "ifdata": "system.attributes.int", + "matches": "8", + "text": "INT: C (d8) {newline} {newline}" + }, + { + "type": "match", + "ifdata": "system.attributes.int", + "matches": 10, + "text": "INT: B (d10) {newline} {newline}" + }, + { + "type": "match", + "ifdata": "system.attributes.int", + "matches": "10", + "text": "INT: B (d10) {newline} {newline}" + }, + { + "type": "match", + "ifdata": "system.attributes.int", + "matches": 12, + "text": "INT: A (d12) {newline} {newline}" + }, + { + "type": "match", + "ifdata": "system.attributes.int", + "matches": "12", + "text": "INT: A (d12) {newline} {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.medicalAid", + "matches": "0", + "text": "MedAid: -- {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.medicalAid", + "matches": 0, + "text": "MedAid: -- {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.medicalAid", + "matches": 6, + "text": "MedAid: D (d6) {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.medicalAid", + "matches": "6", + "text": "MedAid: D (d6) {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.medicalAid", + "matches": 8, + "text": "MedAid: C (d8) {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.medicalAid", + "matches": "8", + "text": "MedAid: C (d8) {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.medicalAid", + "matches": 10, + "text": "MedAid: B (d10) {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.medicalAid", + "matches": "10", + "text": "MedAid: B (d10) {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.medicalAid", + "matches": 12, + "text": "MedAid: A (d12) {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.medicalAid", + "matches": "12", + "text": "MedAid: A (d12) {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.observation", + "matches": "0", + "text": "Observ: -- {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.observation", + "matches": 0, + "text": "Observ: -- {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.observation", + "matches": 6, + "text": "Observ: D (d6) {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.observation", + "matches": "6", + "text": "Observ: D (d6) {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.observation", + "matches": 8, + "text": "Observ: C (d8) {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.observation", + "matches": "8", + "text": "Observ: C (d8) {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.observation", + "matches": 10, + "text": "Observ: B (d10) {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.observation", + "matches": "10", + "text": "Observ: B (d10) {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.observation", + "matches": 12, + "text": "Observ: A (d12) {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.observation", + "matches": "12", + "text": "Observ: A (d12) {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.tech", + "matches": "0", + "text": "Tech: -- {newline} {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.tech", + "matches": 0, + "text": "Tech: -- {newline} {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.tech", + "matches": 6, + "text": "Tech: D (d6) {newline} {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.tech", + "matches": "6", + "text": "Tech: D (d6) {newline} {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.tech", + "matches": 8, + "text": "Tech: C (d8) {newline} {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.tech", + "matches": "8", + "text": "Tech: C (d8) {newline} {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.tech", + "matches": 10, + "text": "Tech: B (d10) {newline} {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.tech", + "matches": "10", + "text": "Tech: B (d10) {newline} {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.tech", + "matches": 12, + "text": "Tech: A (d12) {newline} {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.tech", + "matches": "12", + "text": "Tech: A (d12) {newline} {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.driving", + "matches": "0", + "text": "Driving*: --" + }, + { + "type": "match", + "ifdata": "system.skills.driving", + "matches": 0, + "text": "Driving*: --" + }, + { + "type": "match", + "ifdata": "system.skills.driving", + "matches": 6, + "text": "Driving*: D (d6)" + }, + { + "type": "match", + "ifdata": "system.skills.driving", + "matches": "6", + "text": "Driving*: D (d6)" + }, + { + "type": "match", + "ifdata": "system.skills.driving", + "matches": 8, + "text": "Driving*: C (d8)" + }, + { + "type": "match", + "ifdata": "system.skills.driving", + "matches": "8", + "text": "Driving*: C (d8)" + }, + { + "type": "match", + "ifdata": "system.skills.driving", + "matches": 10, + "text": "Driving*: B (d10)" + }, + { + "type": "match", + "ifdata": "system.skills.driving", + "matches": "10", + "text": "Driving*: B (d10)" + }, + { + "type": "match", + "ifdata": "system.skills.driving", + "matches": 12, + "text": "Driving*: A (d12)" + }, + { + "type": "match", + "ifdata": "system.skills.driving", + "matches": "12", + "text": "Driving*: A (d12)" + } + ] + }, + { + "name": "EMP Group", + "type": "direct-complex", + "minwidth": 80, + "align": "left", + "valign": "top", + "header": "show", + "text": [ + { + "type": "match", + "ifdata": "system.attributes.emp", + "matches": 0, + "text": "EMP: -- {newline} {newline}" + }, + { + "type": "match", + "ifdata": "system.attributes.emp", + "matches": "0", + "text": "EMP: -- {newline} {newline}" + }, + { + "type": "match", + "ifdata": "system.attributes.emp", + "matches": 6, + "text": "EMP: D (d6) {newline} {newline}" + }, + { + "type": "match", + "ifdata": "system.attributes.emp", + "matches": "6", + "text": "EMP: D (d6) {newline} {newline}" + }, + { + "type": "match", + "ifdata": "system.attributes.emp", + "matches": 8, + "text": "EMP: C (d8) {newline} {newline}" + }, + { + "type": "match", + "ifdata": "system.attributes.emp", + "matches": "8", + "text": "EMP: C (d8) {newline} {newline}" + }, + { + "type": "match", + "ifdata": "system.attributes.emp", + "matches": 10, + "text": "EMP: B (d10) {newline} {newline}" + }, + { + "type": "match", + "ifdata": "system.attributes.emp", + "matches": "10", + "text": "EMP: B (d10) {newline} {newline}" + }, + { + "type": "match", + "ifdata": "system.attributes.emp", + "matches": 12, + "text": "EMP: A (d12) {newline} {newline}" + }, + { + "type": "match", + "ifdata": "system.attributes.emp", + "matches": "12", + "text": "EMP: A (d12) {newline} {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.connections", + "matches": "0", + "text": "Conn: -- {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.connections", + "matches": 0, + "text": "Conn: -- {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.connections", + "matches": 6, + "text": "Conn: D (d6) {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.connections", + "matches": "6", + "text": "Conn: D (d6) {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.connections", + "matches": 8, + "text": "Conn: C (d8) {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.connections", + "matches": "8", + "text": "Conn: C (d8) {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.connections", + "matches": 10, + "text": "Conn: B (d10) {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.connections", + "matches": "10", + "text": "Conn: B (d10) {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.connections", + "matches": 12, + "text": "Conn: A (d12) {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.connections", + "matches": "12", + "text": "Conn: A (d12) {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.insight", + "matches": "0", + "text": "Insight: -- {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.insight", + "matches": 0, + "text": "Insight: -- {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.insight", + "matches": 6, + "text": "Insight: D (d6) {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.insight", + "matches": "6", + "text": "Insight: D (d6) {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.insight", + "matches": 8, + "text": "Insight: C (d8) {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.insight", + "matches": "8", + "text": "Insight: C (d8) {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.insight", + "matches": 10, + "text": "Insight: B (d10) {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.insight", + "matches": "10", + "text": "Insight: B (d10) {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.insight", + "matches": 12, + "text": "Insight: A (d12) {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.insight", + "matches": "12", + "text": "Insight: A (d12) {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.manipulation", + "matches": "0", + "text": "Manip: -- {newline} {newline}" + }, + { + "type": "match", + "ifdata": "system.skills.manipulation", + "matches": 0, + "text": "Manip: --" + }, + { + "type": "match", + "ifdata": "system.skills.manipulation", + "matches": 6, + "text": "Manip: D (d6)" + }, + { + "type": "match", + "ifdata": "system.skills.manipulation", + "matches": "6", + "text": "Manip: D (d6)" + }, + { + "type": "match", + "ifdata": "system.skills.manipulation", + "matches": 8, + "text": "Manip: C (d8)" + }, + { + "type": "match", + "ifdata": "system.skills.manipulation", + "matches": "8", + "text": "Manip: C (d8)" + }, + { + "type": "match", + "ifdata": "system.skills.manipulation", + "matches": 10, + "text": "Manip: B (d10)" + }, + { + "type": "match", + "ifdata": "system.skills.manipulation", + "matches": "10", + "text": "Manip: B (d10)" + }, + { + "type": "match", + "ifdata": "system.skills.manipulation", + "matches": 12, + "text": "Manip: A (d12)" + }, + { + "type": "match", + "ifdata": "system.skills.manipulation", + "matches": "12", + "text": "Manip: A (d12)" + } + ] + }, + { + "name": "Chin", + "type": "direct", + "align": "center", + "valign": "top", + "header": "show", + "text": "system.metaCurrencies.chinyen" + }, + { + "name": "Hum", + "type": "direct", + "align": "center", + "valign": "top", + "header": "show", + "text": "system.metaCurrencies.humanity" + }, + { + "name": "Promo", + "type": "direct", + "align": "center", + "valign": "top", + "header": "show", + "text": "system.metaCurrencies.promotion" + } + ] + ] +} \ No newline at end of file diff --git a/example_templates/dnd5e_template.json b/example_templates/dnd5e_template.json new file mode 100644 index 0000000..27d54d7 --- /dev/null +++ b/example_templates/dnd5e_template.json @@ -0,0 +1,175 @@ +{ + "name": "dnd5e", + "system": "dnd5e", + "author": "Your Name Here", + "offline_excludes": [ + "npc", + "base", + "vehicle", + "group" + ], + "rows": [ + [ + { + "name": "Character Sheet", + "type": "charactersheet", + "header": "hide", + "text": "" + }, + { + "name": "Name", + "type": "direct", + "header": "show", + "text": "name {newline} system.details.race" + }, + { + "name": "STR", + "type": "direct", + "header": "show", + "text": "system.abilities.str.value" + }, + { + "name": "DEX", + "type": "direct", + "header": "show", + "text": "system.abilities.dex.value" + }, + { + "name": "CON", + "type": "direct", + "header": "show", + "text": "system.abilities.con.value" + }, + { + "name": "INT", + "type": "direct", + "header": "show", + "text": "system.abilities.int.value" + }, + { + "name": "WIS", + "type": "direct", + "header": "show", + "text": "system.abilities.wis.value" + }, + { + "name": "CHA", + "type": "direct", + "header": "show", + "text": "system.abilities.cha.value" + }, + { + "name": "AC", + "type": "direct", + "header": "show", + "text": "system.attributes.ac.value" + }, + { + "name": "Inv", + "type": "direct", + "header": "show", + "text": "system.skills.inv.passive" + }, + { + "name": "Vision", + "type": "string", + "header": "show", + "text": "" + } + ], + [ + { + "name": "Spacer1", + "type": "", + "header": "hide", + "text": "" + }, + { + "name": "Classes", + "type": "array-string-builder", + "header": "show", + "text": "classes => name - system.levels" + }, + { + "name": "STR Mod", + "type": "direct", + "header": "hide", + "text": "system.abilities.str.mod" + }, + { + "name": "DEX Mod", + "type": "direct", + "header": "hide", + "text": "system.abilities.dex.mod" + }, + { + "name": "CON Mod", + "type": "direct", + "header": "hide", + "text": "system.abilities.con.mod" + }, + { + "name": "INT Mod", + "type": "direct", + "header": "hide", + "text": "system.abilities.int.mod" + }, + { + "name": "WIS Mod", + "type": "direct", + "header": "hide", + "text": "system.abilities.wis.mod" + }, + { + "name": "CHA Mod", + "type": "direct", + "header": "hide", + "text": "system.abilities.cha.mod" + }, + { + "name": "Per", + "type": "direct", + "header": "show", + "text": "system.skills.prc.passive" + }, + { + "name": "Ins", + "type": "direct", + "header": "show", + "text": "system.skills.ins.passive" + }, + { + "name": "Senses", + "type": "direct-complex", + "header": "hide", + "text": [ + { + "type": "exists", + "value": "system.attributes.senses.darkvision", + "text": "Darkvision: system.attributes.senses.darkvision" + }, + { + "type": "exists", + "value": "system.attributes.senses.blindsight", + "text": "Blindsight: system.attributes.senses.blindsight" + }, + { + "type": "exists", + "value": "system.attributes.senses.tremorsense", + "text": "Tremorsense: system.attributes.senses.tremorsense" + }, + { + "type": "exists", + "value": "system.attributes.senses.truesight", + "text": "Truesight: system.attributes.senses.truesight" + }, + { + "type": "exists", + "value": "system.attributes.senses.special", + "text": "Special: system.attributes.senses.special" + } + ] + } + ] + ] +} \ No newline at end of file diff --git a/example_templates/dragonbane-name.json b/example_templates/dragonbane-name.json new file mode 100644 index 0000000..99da046 --- /dev/null +++ b/example_templates/dragonbane-name.json @@ -0,0 +1,220 @@ +{ + "name": "Dragonbane - With Name", + "system": "dragonbane", + "author": "Michael Card (Emo Cthulhu)", + "offline_excludes": [ + "npc", + "base", + "monster" + ], + "rows": [ + [ + { + "name": "Character Sheet", + "align": "center", + "type": "charactersheet", + "header": "hide", + "text": "" + }, + { + "name": "Name", + "align": "left", + "maxwidth": 100, + "type": "direct", + "header": "show", + "text": "name" + }, + { + "name": "Age & Kin", + "align": "center", + "type": "direct", + "header": "show", + "text": "Age: system.age {newline} Kin: system.kin.name" + }, + { + "name": "Hit Points", + "align": "center", + "valign": "bottom", + "type": "direct", + "header": "show", + "text": "system.hitPoints / system.hitPoints.max {newline} {newline}" + }, + { + "name": "STR", + "align": "center", + "valign": "bottom", + "type": "direct-complex", + "header": "show", + "text": [ + { + "type": "match", + "ifdata": "system.conditions.str", + "matches": true, + "text": "system.attributes.str {newline} Exhaust", + "else": "system.attributes.str {newline} {newline}" + } + ] + }, + { + "name": "CON", + "align": "center", + "valign": "bottom", + "type": "direct-complex", + "header": "show", + "text": [ + { + "type": "match", + "ifdata": "system.conditions.con", + "matches": true, + "text": "system.attributes.con {newline} Sickly", + "else": "system.attributes.con {newline} {newline}" + } + ] + }, + { + "name": "AGL", + "align": "center", + "valign": "bottom", + "type": "direct-complex", + "header": "show", + "text": [ + { + "type": "match", + "ifdata": "system.conditions.agl", + "matches": true, + "text": "system.attributes.agl {newline} Dazed", + "else": "system.attributes.agl {newline} {newline}" + } + ] + }, + { + "name": "INT", + "align": "center", + "valign": "bottom", + "type": "direct-complex", + "header": "show", + "text": [ + { + "type": "match", + "ifdata": "system.conditions.int", + "matches": true, + "text": "system.attributes.int {newline} Angry", + "else": "system.attributes.int {newline} {newline}" + } + ] + }, + { + "name": "WIL", + "align": "center", + "valign": "bottom", + "type": "direct-complex", + "header": "show", + "text": [ + { + "type": "match", + "ifdata": "system.conditions.wil", + "matches": true, + "text": "system.attributes.wil {newline} Scared", + "else": "system.attributes.wil {newline} {newline}" + } + ] + }, + { + "name": "CHA", + "align": "center", + "valign": "bottom", + "type": "direct-complex", + "header": "show", + "text": [ + { + "type": "match", + "ifdata": "system.conditions.cha", + "matches": true, + "text": "system.attributes.cha {newline} Disheart", + "else": "system.attributes.cha {newline} {newline}" + } + ] + } + ], + [ + { + "name": ".", + "align": "center", + "type": "direct", + "header": "hide", + "text": "" + }, + { + "name": "", + "align": "center", + "type": "direct", + "header": "show", + "text": "" + }, + { + "name": "Profession", + "align": "center", + "valign": "top", + "type": "direct", + "header": "show", + "text": "system.profession.name" + }, + { + "name": "Will Points", + "align": "center", + "valign": "top", + "type": "direct", + "header": "show", + "text": "system.willPoints / system.willPoints.max" + }, + { + "name": "DB-STR", + "align": "center", + "valign": "top", + "type": "direct", + "header": "show", + "text": "system.damageBonus.str" + }, + { + "name": "Move", + "align": "center", + "valign": "top", + "type": "direct", + "header": "show", + "text": "system.movement" + }, + { + "name": "DB-AGL", + "align": "center", + "valign": "top", + "type": "direct", + "header": "show", + "text": "system.damageBonus.agl" + }, + { + "name": "Copper", + "align": "center", + "valign": "top", + "type": "direct", + "header": "show", + "text": "system.currency.cc" + }, + { + "name": "Silver", + "align": "center", + "valign": "top", + "type": "direct", + "header": "show", + "text": "system.currency.sc" + }, + { + "name": "Gold", + "align": "center", + "valign": "top", + "type": "direct", + "header": "show", + "text": "system.currency.gc" + } + ] + ] +} \ No newline at end of file diff --git a/example_templates/dragonbane-no-name.json b/example_templates/dragonbane-no-name.json new file mode 100644 index 0000000..7f46ecc --- /dev/null +++ b/example_templates/dragonbane-no-name.json @@ -0,0 +1,204 @@ +{ + "name": "Dragonbane - No Name", + "system": "dragonbane", + "author": "Michael Card (Emo Cthulhu)", + "offline_excludes": [ + "npc", + "base", + "monster" + ], + "rows": [ + [ + { + "name": "Character Sheet", + "align": "center", + "type": "charactersheet", + "header": "hide", + "text": "" + }, + { + "name": "Age & Kin", + "align": "center", + "type": "direct", + "header": "show", + "text": "Age: system.age {newline} Kin: system.kin.name" + }, + { + "name": "Hit Points", + "align": "center", + "valign": "bottom", + "type": "direct", + "header": "show", + "text": "system.hitPoints / system.hitPoints.max {newline} {newline}" + }, + { + "name": "STR", + "align": "center", + "valign": "bottom", + "type": "direct-complex", + "header": "show", + "text": [ + { + "type": "match", + "ifdata": "system.conditions.str", + "matches": true, + "text": "system.attributes.str {newline} Exhaust", + "else": "system.attributes.str {newline} {newline}" + } + ] + }, + { + "name": "CON", + "align": "center", + "valign": "bottom", + "type": "direct-complex", + "header": "show", + "text": [ + { + "type": "match", + "ifdata": "system.conditions.con", + "matches": true, + "text": "system.attributes.con {newline} Sickly", + "else": "system.attributes.con {newline} {newline}" + } + ] + }, + { + "name": "AGL", + "align": "center", + "valign": "bottom", + "type": "direct-complex", + "header": "show", + "text": [ + { + "type": "match", + "ifdata": "system.conditions.agl", + "matches": true, + "text": "system.attributes.agl {newline} Dazed", + "else": "system.attributes.agl {newline} {newline}" + } + ] + }, + { + "name": "INT", + "align": "center", + "valign": "bottom", + "type": "direct-complex", + "header": "show", + "text": [ + { + "type": "match", + "ifdata": "system.conditions.int", + "matches": true, + "text": "system.attributes.int {newline} Angry", + "else": "system.attributes.int {newline} {newline}" + } + ] + }, + { + "name": "WIL", + "align": "center", + "valign": "bottom", + "type": "direct-complex", + "header": "show", + "text": [ + { + "type": "match", + "ifdata": "system.conditions.wil", + "matches": true, + "text": "system.attributes.wil {newline} Scared", + "else": "system.attributes.wil {newline} {newline}" + } + ] + }, + { + "name": "CHA", + "align": "center", + "valign": "bottom", + "type": "direct-complex", + "header": "show", + "text": [ + { + "type": "match", + "ifdata": "system.conditions.cha", + "matches": true, + "text": "system.attributes.cha {newline} Disheart", + "else": "system.attributes.cha {newline} {newline}" + } + ] + } + ], + [ + { + "name": "", + "type": "direct", + "header": "hide", + "text": "" + }, + { + "name": "Profession", + "align": "center", + "valign": "top", + "type": "direct", + "header": "show", + "text": "system.profession.name" + }, + { + "name": "Will Points", + "align": "center", + "valign": "top", + "type": "direct", + "header": "show", + "text": "system.willPoints / system.willPoints.max" + }, + { + "name": "DB-STR", + "align": "center", + "valign": "top", + "type": "direct", + "header": "show", + "text": "system.damageBonus.str" + }, + { + "name": "Move", + "align": "center", + "valign": "top", + "type": "direct", + "header": "show", + "text": "system.movement" + }, + { + "name": "DB-AGL", + "align": "center", + "valign": "top", + "type": "direct", + "header": "show", + "text": "system.damageBonus.agl" + }, + { + "name": "Copper", + "align": "center", + "valign": "top", + "type": "direct", + "header": "show", + "text": "system.currency.cc" + }, + { + "name": "Silver", + "align": "center", + "valign": "top", + "type": "direct", + "header": "show", + "text": "system.currency.sc" + }, + { + "name": "Gold", + "align": "center", + "valign": "top", + "type": "direct", + "header": "show", + "text": "system.currency.gc" + } + ] + ] +} \ No newline at end of file diff --git a/example_templates/starfinder.json b/example_templates/starfinder.json new file mode 100644 index 0000000..ef032b6 --- /dev/null +++ b/example_templates/starfinder.json @@ -0,0 +1,410 @@ +{ + "name": "Starfinder", + "system": "sfrpg", + "author": "Michael Card (Emo Cthulhu)", + "offline_excludes": [ + "npc", + "npc2", + "base", + "creature", + "drone", + "hazard", + "vehicle", + "starship" + ], + "rows": [ + [ + { + "name": "x", + "type": "charactersheet", + "align": "left", + "header": "hide", + "text": "" + }, + { + "name": "Details", + "type": "direct", + "align": "left", + "header": "show", + "text": "name {newline} Theme: system.details.theme {newline} Race: system.details.race {newline} Size: system.traits.size" + }, + { + "name": "STR", + "type": "direct", + "align": "center", + "valign": "top", + "header": "show", + "text": "system.abilities.str {newline} system.abilities.str.mod" + }, + { + "name": "DEX", + "type": "direct", + "align": "center", + "valign": "top", + "header": "show", + "text": "system.abilities.dex {newline} system.abilities.dex.mod" + }, + { + "name": "CON", + "type": "direct", + "align": "center", + "valign": "top", + "header": "show", + "text": "system.abilities.con {newline} system.abilities.con.mod" + }, + { + "name": "INT", + "type": "direct", + "align": "center", + "valign": "top", + "header": "show", + "text": "system.abilities.int {newline} system.abilities.int.mod" + }, + { + "name": "WIS", + "type": "direct", + "align": "center", + "valign": "top", + "header": "show", + "text": "system.abilities.wis {newline} system.abilities.wis.mod" + }, + { + "name": "CHA", + "type": "direct", + "align": "center", + "valign": "top", + "header": "show", + "text": "system.abilities.cha {newline} system.abilities.cha.mod" + }, + { + "name": "HP/SP", + "type": "direct", + "align": "center", + "valign": "top", + "header": "show", + "text": "HP: system.attributes.hp.value / system.attributes.hp.max {newline} SP: system.attributes.sp.value / system.attributes.sp.max" + }, + { + "name": "EAC", + "type": "direct", + "align": "center", + "valign": "top", + "header": "show", + "text": "system.attributes.eac" + }, + { + "name": "BAB", + "type": "direct", + "align": "center", + "valign": "top", + "header": "show", + "text": "system.attributes.baseAttackBonus" + }, + { + "name": "Main Move", + "type": "direct", + "align": "left", + "valign": "top", + "header": "show", + "text": "Type: system.attributes.speed.mainMovement" + }, + { + "name": "Fort", + "type": "direct", + "align": "center", + "valign": "top", + "header": "show", + "text": "system.attributes.fort.bonus" + }, + { + "name": "Reflex", + "type": "direct", + "align": "center", + "valign": "top", + "header": "show", + "text": "system.attributes.reflex.bonus" + }, + { + "name": "Will", + "type": "direct", + "align": "center", + "valign": "top", + "header": "show", + "text": "system.attributes.will.bonus" + }, + { + "name": "Senses", + "type": "direct", + "maxwidth": 125, + "align": "left", + "valign": "top", + "header": "show", + "text": "system.traits.senses" + } + ], + [ + { + "name": "blank1", + "align": "left", + "type": "direct", + "header": "hide", + "text": "" + }, + { + "name": "Class(es)/Levels", + "type": "direct-complex", + "align": "left", + "valign": "top", + "header": "show", + "text": [ + { + "type": "exists", + "value": "system.details.level", + "text": "Level: system.details.level {newline}" + }, + { + "type": "exists", + "value": "system.classes.solarian.levels", + "text": "Solarian system.classes.solarian.levels {newline}" + }, + { + "type": "exists", + "value": "system.classes.soldier.levels", + "text": "Soldier system.classes.soldier.levels {newline}" + }, + { + "type": "exists", + "value": "system.classes.operative.levels", + "text": "Operative system.classes.operative.levels {newline}" + }, + { + "type": "exists", + "value": "system.classes.mechanic.levels", + "text": "Mechanic system.classes.mechanic.levels {newline}" + }, + { + "type": "exists", + "value": "system.classes.mystic.levels", + "text": "Mystic system.classes.mystic.levels {newline}" + }, + { + "type": "exists", + "value": "system.classes.technomancer.levels", + "text": "Technomancer system.classes.technomancer.levels {newline}" + }, + { + "type": "exists", + "value": "system.classes.envoy.levels", + "text": "Envoy system.classes.envoy.levels {newline}" + }, + { + "type": "exists", + "value": "system.classes.witchwarper.levels", + "text": "Witchwarper system.classes.witchwarper.levels {newline}" + }, + { + "type": "exists", + "value": "system.classes.vanguard.levels", + "text": "Vanguard system.classes.vanguard.levels {newline}" + }, + { + "type": "exists", + "value": "system.classes.biohacker.levels", + "text": "Biohacker system.classes.biohacker.levels" + } + ] + }, + { + "name": "STRKEY?", + "type": "direct-complex", + "align": "center", + "valign": "top", + "header": "hide", + "text": [ + { + "type": "match", + "ifdata": "system.attributes.keyability", + "matches": "str", + "text": "KEY" + } + ] + }, + { + "name": "DEXKEY?", + "type": "direct-complex", + "align": "center", + "valign": "top", + "header": "hide", + "text": [ + { + "type": "match", + "ifdata": "system.attributes.keyability", + "matches": "dex", + "text": "KEY" + } + ] + }, + { + "name": "CONKEY?", + "type": "direct-complex", + "align": "center", + "valign": "top", + "header": "hide", + "text": [ + { + "type": "match", + "ifdata": "system.attributes.keyability", + "matches": "con", + "text": "KEY" + } + ] + }, + { + "name": "INTKEY?", + "type": "direct-complex", + "align": "center", + "valign": "top", + "header": "hide", + "text": [ + { + "type": "match", + "ifdata": "system.attributes.keyability", + "matches": "int", + "text": "KEY" + } + ] + }, + { + "name": "WISKEY?", + "type": "direct-complex", + "align": "center", + "valign": "top", + "header": "hide", + "text": [ + { + "type": "match", + "ifdata": "system.attributes.keyability", + "matches": "wis", + "text": "KEY" + } + ] + }, + { + "name": "CHAKEY?", + "type": "direct-complex", + "align": "center", + "valign": "top", + "header": "hide", + "text": [ + { + "type": "match", + "ifdata": "system.attributes.keyability", + "matches": "cha", + "text": "KEY" + } + ] + }, + { + "name": "Resolve", + "type": "direct", + "align": "left", + "valign": "top", + "header": "show", + "text": "RP: system.attributes.rp.value / system.attributes.rp.max" + }, + { + "name": "KAC/CMD", + "type": "direct", + "align": "center", + "valign": "top", + "header": "show", + "text": "system.attributes.kac {newline} system.attributes.cmd" + }, + { + "name": "Init", + "type": "direct", + "align": "center", + "valign": "top", + "header": "show", + "text": "system.attributes.init.total" + }, + { + "name": "Movement", + "type": "direct-complex", + "align": "left", + "valign": "top", + "header": "show", + "text": [ + { + "type": "match", + "ifdata": "system.attributes.speed.climbing.base", + "matches": 0, + "text": "", + "else": "Climbing: system.attributes.speed.climbing.value {newline}" + }, + { + "type": "match", + "ifdata": "system.attributes.speed.flying.base", + "matches": 0, + "text": "", + "else": "Flying: system.attributes.speed.flying.value {newline}" + }, + { + "type": "match", + "ifdata": "system.attributes.speed.burrowing.base", + "matches": 0, + "text": "", + "else": "Burrow: system.attributes.speed.burrowing.value {newline}" + }, + { + "type": "match", + "ifdata": "system.attributes.speed.swimming.base", + "matches": 0, + "text": "", + "else": "Swimming: system.attributes.speed.swimming.value {newline}" + }, + { + "type": "match", + "ifdata": "system.attributes.speed.land", + "matches": 0, + "text": "", + "else": "Land: system.attributes.speed.land.value" + } + ] + }, + { + "name": "Reach", + "type": "direct", + "align": "center", + "valign": "top", + "header": "show", + "text": "system.attributes.reach" + }, + { + "name": "Space", + "type": "direct", + "align": "center", + "valign": "top", + "header": "show", + "text": "system.attributes.space" + }, + { + "name": "Arms", + "type": "direct", + "align": "center", + "valign": "top", + "header": "show", + "text": "system.attributes.arms" + }, + { + "name": "Languages", + "type": "array-string-builder", + "align": "left", + "valign": "top", + "maxwidth": 125, + "header": "show", + "text": "system.traits.languages => value, " + } + ] + ] +} \ No newline at end of file diff --git a/example_templates/twdu-anchors.json b/example_templates/twdu-anchors.json new file mode 100644 index 0000000..4c4e3c5 --- /dev/null +++ b/example_templates/twdu-anchors.json @@ -0,0 +1,104 @@ + { + "name": "The Walking Dead Universe RPG - With Anchors", + "system": "twdu", + "author": "Michael Card (Emo Cthulhu)", + "offline_excludes": [ + "npc", + "base", + "vehicle", + "haven", + "animal" + ], + "rows": [ + [ + { + "name": "xx", + "type": "charactersheet", + "align": "center", + "header": "hide", + "text": "" + }, + { + "name": "Name", + "type": "direct", + "maxwidth": 160, + "align": "left", + "header": "show", + "text": "name {newline} Archetype: system.archetype" + }, + { + "name": "Health", + "minwidth": 50, + "type": "direct", + "align": "center", + "valign": "top", + "header": "show", + "text": "system.health / 3" + }, + { + "name": "Stress", + "minwidth": 50, + "type": "direct", + "align": "center", + "valign": "top", + "header": "show", + "text": "system.stress" + }, + { + "name": "Anchor(s)", + "type": "direct-complex", + "align": "left", + "valign": "top", + "header": "show", + "text": [ + { + "type": "exists", + "value": "system.pcAnchor", + "text": "PC: {newline} system.pcAnchor {newline} {newline}" + }, + { + "type": "exists", + "value": "system.npcAnchor", + "text": "NPC: {newline} system.npcAnchor" + } + ] + }, + { + "name": "STR Group", + "minwidth": 50, + "type": "direct", + "align": "left", + "valign": "top", + "header": "show", + "text": "STR: system.attributes.str {newline} {newline} CC: system.skills.closeCombat / system.skills.closeCombat {+} system.attributes.str {newline} End: system.skills.endure / system.skills.endure {+} system.attributes.str {newline} For: system.skills.force / system.skills.force {+} system.attributes.str" + }, + { + "name": "AGL Group", + "minwidth": 50, + "type": "direct", + "align": "left", + "valign": "top", + "header": "show", + "text": "AGL: system.attributes.agl {newline} {newline} Mob: system.skills.mobility / system.skills.mobility {+} system.attributes.agl {newline} RC: system.skills.rangedCombat / system.skills.rangedCombat {+} system.attributes.agl {newline} St: system.skills.stealth / system.skills.stealth {+} system.attributes.agl" + }, + { + "name": "WIT Group", + "minwidth": 50, + "type": "direct", + "align": "left", + "valign": "top", + "header": "show", + "text": "WIT: system.attributes.wit {newline} {newline} Sco: system.skills.scout / system.skills.scout {+} system.attributes.wit {newline} Sur: system.skills.survival / system.skills.survival {+} system.attributes.wit {newline} Tech: system.skills.tech / system.skills.tech {+} system.attributes.wit" + }, + { + "name": "EMP Group", + "minwidth": 50, + "type": "direct", + "align": "left", + "valign": "top", + "header": "show", + "text": "EMP: system.attributes.emp {newline} {newline} Lead: system.skills.leadership / system.skills.leadership {+} system.attributes.emp {newline} Man: system.skills.manipulation / system.skills.manipulation {+} system.attributes.emp {newline} Med: system.skills.medicine / system.skills.medicine {+} system.attributes.emp" + } + ] + ] + } \ No newline at end of file diff --git a/example_templates/twdu-no-anchors.json b/example_templates/twdu-no-anchors.json new file mode 100644 index 0000000..c9f9990 --- /dev/null +++ b/example_templates/twdu-no-anchors.json @@ -0,0 +1,76 @@ + { + "name": "The Walking Dead Universe RPG - No Anchors", + "system": "twdu", + "author": "Michael Card (Emo Cthulhu)", + "offline_excludes": [ + "npc", + "base", + "vehicle", + "haven", + "animal" + ], + "rows": [ + [ + { + "name": "xx", + "type": "charactersheet", + "align": "center", + "header": "hide", + "text": "" + }, + { + "name": "Name", + "type": "direct", + "maxwidth": 160, + "align": "left", + "header": "show", + "text": "name {newline} Archetype: system.archetype" + }, + { + "name": "Health/Stress", + "minwidth": 50, + "type": "direct", + "align": "center", + "valign": "top", + "header": "show", + "text": "HP: system.health / 3 {newline} SP: system.stress" + }, + { + "name": "STR Group", + "minwidth": 50, + "type": "direct", + "align": "left", + "valign": "top", + "header": "show", + "text": "STR: system.attributes.str {newline} {newline} CC: system.skills.closeCombat / system.skills.closeCombat {+} system.attributes.str {newline} End: system.skills.endure / system.skills.endure {+} system.attributes.str {newline} For: system.skills.force / system.skills.force {+} system.attributes.str" + }, + { + "name": "AGL Group", + "minwidth": 50, + "type": "direct", + "align": "left", + "valign": "top", + "header": "show", + "text": "AGL: system.attributes.agl {newline} {newline} Mob: system.skills.mobility / system.skills.mobility {+} system.attributes.agl {newline} RC: system.skills.rangedCombat / system.skills.rangedCombat {+} system.attributes.agl {newline} St: system.skills.stealth / system.skills.stealth {+} system.attributes.agl" + }, + { + "name": "WIT Group", + "minwidth": 50, + "type": "direct", + "align": "left", + "valign": "top", + "header": "show", + "text": "WIT: system.attributes.wit {newline} {newline} Sco: system.skills.scout / system.skills.scout {+} system.attributes.wit {newline} Sur: system.skills.survival / system.skills.survival {+} system.attributes.wit {newline} Tech: system.skills.tech / system.skills.tech {+} system.attributes.wit" + }, + { + "name": "EMP Group", + "minwidth": 50, + "type": "direct", + "align": "left", + "valign": "top", + "header": "show", + "text": "EMP: system.attributes.emp {newline} {newline} Lead: system.skills.leadership / system.skills.leadership {+} system.attributes.emp {newline} Man: system.skills.manipulation / system.skills.manipulation {+} system.attributes.emp {newline} Med: system.skills.medicine / system.skills.medicine {+} system.attributes.emp" + } + ] + ] + } \ No newline at end of file diff --git a/example_templates/twdu-two-rows.json b/example_templates/twdu-two-rows.json new file mode 100644 index 0000000..21fc412 --- /dev/null +++ b/example_templates/twdu-two-rows.json @@ -0,0 +1,110 @@ + { + "name": "The Walking Dead Universe RPG - Two Rows", + "system": "twdu", + "author": "Michael Card (Emo Cthulhu)", + "offline_excludes": [ + "npc", + "base", + "vehicle", + "haven", + "animal" + ], + "rows": [ + [ + { + "name": "xx", + "type": "charactersheet", + "align": "center", + "header": "hide", + "text": "" + }, + { + "name": "Name", + "type": "direct", + "minwidth": 130, + "align": "left", + "header": "show", + "text": "name {newline} Archetype: system.archetype" + }, + { + "name": "HP/SP", + "minwidth": 130, + "type": "direct", + "align": "left", + "valign": "top", + "header": "show", + "text": "HP: system.health / 3 {newline} SP: system.stress" + }, + { + "name": "PC Anchor(s)", + "minwidth": 130, + "type": "direct-complex", + "align": "left", + "valign": "top", + "header": "show", + "text": [ + { + "type": "exists", + "value": "system.pcAnchor", + "text": "PC: {newline} system.pcAnchor" + } + ] + }, + { + "name": "NPC Anchor(s)", + "minwidth": 130, + "type": "direct-complex", + "align": "left", + "valign": "top", + "header": "show", + "text": [ + { + "type": "exists", + "value": "system.npcAnchor", + "text": "NPC: {newline} system.npcAnchor" + } + ] + } + ], + [ + { + "name": "xxx", + "type": "direct", + "header": "hide", + "text": "" + }, + { + "name": "STR Group", + "type": "direct", + "align": "left", + "valign": "top", + "header": "show", + "text": "STRENGTH: system.attributes.str {newline} {newline} Close Combat: system.skills.closeCombat / system.skills.closeCombat {+} system.attributes.str {newline} Endure: system.skills.endure / system.skills.endure {+} system.attributes.str {newline} Force: system.skills.force / system.skills.force {+} system.attributes.str" + }, + { + "name": "AGL Group", + "type": "direct", + "align": "left", + "valign": "top", + "header": "show", + "text": "AGILITY: system.attributes.agl {newline} {newline} Mobility: system.skills.mobility / system.skills.mobility {+} system.attributes.agl {newline} Ranged Combat: system.skills.rangedCombat / system.skills.rangedCombat {+} system.attributes.agl {newline} Stealth: system.skills.stealth / system.skills.stealth {+} system.attributes.agl" + }, + { + "name": "WIT Group", + "type": "direct", + "align": "left", + "valign": "top", + "header": "show", + "text": "WITS: system.attributes.wit {newline} {newline} Scout: system.skills.scout / system.skills.scout {+} system.attributes.wit {newline} Survival: system.skills.survival / system.skills.survival {+} system.attributes.wit {newline} Tech: system.skills.tech / system.skills.tech {+} system.attributes.wit" + }, + { + "name": "EMP Group", + "type": "direct", + "align": "left", + "valign": "top", + "header": "show", + "text": "EMPATHY: system.attributes.emp {newline} {newline} Leadership: system.skills.leadership / system.skills.leadership {+} system.attributes.emp {newline} Manipulation: system.skills.manipulation / system.skills.manipulation {+} system.attributes.emp {newline} Medicine: system.skills.medicine / system.skills.medicine {+} system.attributes.emp" + } + ] + ] + } \ No newline at end of file diff --git a/example_templates/vaesen.json b/example_templates/vaesen.json new file mode 100644 index 0000000..ea96afc --- /dev/null +++ b/example_templates/vaesen.json @@ -0,0 +1,142 @@ +{ + "name": "Vaesen", + "system": "vaesen", + "author": "Michael Card (Emo Cthulhu)", + "offline_excludes": [ + "npc", + "base", + "vaesen", + "headquarter" + ], + "rows": [ + [ + { + "name": "xx", + "type": "charactersheet", + "header": "hide", + "text": "" + }, + { + "name": "Name & Archetype", + "type": "direct", + "align": "left", + "header": "show", + "text": "name {newline} system.bio.archetype" + }, + { + "name": "Physical", + "type": "direct-complex", + "align": "left", + "valign": "top", + "header": "show", + "text": [ + { + "type": "match", + "ifdata": "system.condition.physical.states.exhausted.isChecked", + "matches": true, + "text": "EXHAUSTED {newline}" + }, + { + "type": "match", + "ifdata": "system.condition.physical.states.battered.isChecked", + "matches": true, + "text": "BATTERED {newline}" + }, + { + "type": "match", + "ifdata": "system.condition.physical.states.wounded.isChecked", + "matches": true, + "text": "WOUNDED {newline}" + }, + { + "type": "match", + "ifdata": "system.condition.physical.isBroken", + "matches": true, + "text": "BROKEN" + } + ] + }, + { + "name": "Mental", + "type": "direct-complex", + "align": "left", + "valign": "top", + "header": "show", + "text": [ + { + "type": "match", + "ifdata": "system.condition.mental.states.angry.isChecked", + "matches": true, + "text": "ANGRY {newline}" + }, + { + "type": "match", + "ifdata": "system.condition.mental.states.frightened.isChecked", + "matches": true, + "text": "FRIGHTENED {newline}" + }, + { + "type": "match", + "ifdata": "system.condition.mental.states.hopeless.isChecked", + "matches": true, + "text": "HOPELESS {newline}" + }, + { + "type": "match", + "ifdata": "system.condition.mental.isBroken", + "matches": true, + "text": "BROKEN" + } + ] + }, + { + "name": "Physique", + "type": "direct", + "align": "left", + "valign": "top", + "header": "show", + "text": "PHY: system.attribute.physique {newline} {newline} Agility: system.skill.agility / system.skill.agility {+} system.attribute.physique {newline} ClsCom: system.skill.closeCombat / system.skill.closeCombat {+} system.attribute.physique {newline} Force: system.skill.force / system.skill.force {+} system.attribute.physique" + }, + { + "name": "Precision", + "type": "direct", + "align": "left", + "valign": "top", + "header": "show", + "text": "PRE: system.attribute.precision {newline} {newline} Medic: system.skill.medicine / system.skill.medicine {+} system.attribute.precision {newline} RgCom: system.skill.rangedCombat / system.skill.rangedCombat {+} system.attribute.precision {newline} Stealth: system.skill.stealth / system.skill.stealth {+} system.attribute.precision" + }, + { + "name": "Logic", + "type": "direct", + "align": "left", + "valign": "top", + "header": "show", + "text": "LOG: system.attribute.logic {newline} {newline} Invest: system.skill.investigation / system.skill.investigation {+} system.attribute.logic {newline} Learn: system.skill.learning / system.skill.learning {+} system.attribute.logic {newline} Vigil: system.skill.vigilance / system.skill.vigilance {+} system.attribute.logic" + }, + { + "name": "Empathy", + "type": "direct", + "align": "left", + "valign": "top", + "header": "show", + "text": "EMP: system.attribute.empathy {newline} {newline} Inspir: system.skill.inspiration / system.skill.inspiration {+} system.attribute.empathy {newline} Manip: system.skill.manipulation / system.skill.manipulation {+} system.attribute.empathy {newline} Observ: system.skill.observation / system.skill.observation {+} system.attribute.empathy" + }, + { + "name": "Resources", + "type": "direct", + "align": "center", + "valign": "top", + "header": "show", + "text": "system.resources" + }, + { + "name": "Capital", + "type": "direct", + "align": "center", + "valign": "top", + "header": "show", + "text": "system.capital" + } + ] + ] +} \ No newline at end of file diff --git a/gulpfile.mjs b/gulpfile.mjs index 5845bff..13be3c9 100644 --- a/gulpfile.mjs +++ b/gulpfile.mjs @@ -5,6 +5,7 @@ import fs from "fs-extra"; import gulp from "gulp"; +import { deleteAsync } from "del"; import sass from "gulp-dart-sass"; import sourcemaps from "gulp-sourcemaps"; import path from "node:path"; @@ -16,10 +17,11 @@ import { hideBin } from "yargs/helpers"; import rollupStream from "@rollup/stream"; import rollupConfig from "./rollup.config.mjs"; +import zip from "gulp-zip"; -/** ******************/ +/********************/ /* CONFIGURATION */ -/** ******************/ +/********************/ const packageId = "theater-of-the-mind"; const sourceDirectory = "./src"; @@ -27,24 +29,17 @@ const distDirectory = "./dist"; const stylesDirectory = `${sourceDirectory}/styles`; const stylesExtension = "scss"; const sourceFileExtension = "js"; -const staticFiles = [ - "assets", - "fonts", - "lang", - "packs", - "templates", - "module.json", -]; - -/** ******************/ +const staticFiles = ["assets", "fonts", "lang", "packs", "templates", "module.json"]; + +//*******************/ /* BUILD */ -/** ******************/ +//*******************/ let cache; /** * Build the distributable JavaScript code - * @returns {NodeJS.ReadWriteStream} + * @returns {NodeJS.ReadWriteStream} The built JavaScript code */ function buildCode() { return rollupStream({ ...rollupConfig(), cache }) @@ -60,7 +55,7 @@ function buildCode() { /** * Build style sheets - * @returns {NodeJS.ReadWriteStream} + * @returns {NodeJS.ReadWriteStream} The build style sheets */ function buildStyles() { return gulp @@ -80,20 +75,40 @@ async function copyFiles() { } } +/** + * Cleans the dist folder + * @returns {NodeJS.ReadWriteStream} The cleaned files + */ +async function cleanDist() { + return await deleteAsync([`${distDirectory}/**/*`, `${distDirectory}`]); +} + +/** + * Copies the files ot the dist folder in prep for packaging + * @returns {NodeJS.ReadWriteStream} The copied files + */ +function copyDist() { + // Take everything inside the dist folder and zip it into a subfolder named totm.zip + return gulp.src(`${distDirectory}/**/*`).pipe(gulp.dest(`${distDirectory}/theater-of-the-mind`)); +} + +/** + * Packages the dist subfolderfolder into a zip file + * @returns {NodeJS.ReadWriteStream} The zipped files + */ +function zipDist() { + return gulp + .src(`${distDirectory}/theater-of-the-mind/**/*`, { base: `${distDirectory}` }) + .pipe(zip(`${packageId}.zip`)) + .pipe(gulp.dest(`${distDirectory}`)); +} + /** * Watch for changes for each build step */ export function watch() { - gulp.watch( - `${sourceDirectory}/**/*.${sourceFileExtension}`, - { ignoreInitial: false }, - buildCode, - ); - gulp.watch( - `${stylesDirectory}/**/*.${stylesExtension}`, - { ignoreInitial: false }, - buildStyles, - ); + gulp.watch(`${sourceDirectory}/**/*.${sourceFileExtension}`, { ignoreInitial: false }, buildCode); + gulp.watch(`${stylesDirectory}/**/*.${stylesExtension}`, { ignoreInitial: false }, buildStyles); gulp.watch( staticFiles.map((file) => `${sourceDirectory}/${file}`), { ignoreInitial: false }, @@ -101,14 +116,17 @@ export function watch() { ); } -export const build = gulp.series( - clean, - gulp.parallel(buildCode, buildStyles, copyFiles), -); +export const build = gulp.series(clean, buildCode, buildStyles, copyFiles); //gulp.parallel(buildCode, buildStyles, copyFiles)); + +/********************/ +/* DEV EXPORT */ +/********************/ -/** ******************/ +export const devexport = gulp.series(cleanDist, build, copyDist, zipDist); + +/********************/ /* CLEAN */ -/** ******************/ +/********************/ /** * Remove built files from `dist` folder while ignoring source files @@ -128,13 +146,13 @@ export async function clean() { } } -/** ******************/ +/********************/ /* LINK */ -/** ******************/ +/********************/ /** * Get the data paths of Foundry VTT based on what is configured in `foundryconfig.json` - * @returns {string[]} + * @returns {string[]} The Foundry VTT data path */ function getDataPaths() { const config = fs.readJSONSync("foundryconfig.json"); @@ -150,9 +168,7 @@ function getDataPaths() { ); } if (!fs.existsSync(path.resolve(dataPath))) { - throw new Error( - `The dataPath ${dataPath} does not exist on the file system`, - ); + throw new Error(`The dataPath ${dataPath} does not exist on the file system`); } return path.resolve(dataPath); }); diff --git a/jsconfig.json b/jsconfig.json new file mode 100644 index 0000000..41c7ea2 --- /dev/null +++ b/jsconfig.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "checkJs": true, + "module": "CommonJS", + "target": "ES2021" + }, + "exclude": ["node_modules"], + "include": ["src/**/*", "test/utils.tests.js"] +} diff --git a/package-lock.json b/package-lock.json index 556e012..e55c559 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,18 +1,24 @@ { "name": "theater-of-the-mind", - "version": "1.3.0", + "version": "1.4.8", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "theater-of-the-mind", - "version": "1.3.0", + "version": "1.4.8", "hasInstallScript": true, "license": "MIT", + "dependencies": { + "eslint-plugin-jsdoc": "^46.9.1", + "typescript": "^5.3.3" + }, "devDependencies": { "@rollup/plugin-node-resolve": "^15.2.1", "@rollup/stream": "^3.0.0", "@typhonjs-fvtt/eslint-config-foundry.js": "^0.8.0", + "cross-env": "^7.0.3", + "del": "^7.1.0", "eslint": "^8.49.0", "eslint-config-prettier": "^9.0.0", "eslint-plugin-jest": "^27.4.2", @@ -21,6 +27,7 @@ "gulp": "^4.0.2", "gulp-dart-sass": "^1.1.0", "gulp-sourcemaps": "^3.0.0", + "gulp-zip": "^6.0.0", "husky": "^8.0.3", "jest": "^29.7.0", "jest-environment-jsdom": "^29.7.0", @@ -38,7 +45,6 @@ "version": "1.2.6", "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -711,11 +717,23 @@ "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", "dev": true }, + "node_modules/@es-joy/jsdoccomment": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.41.0.tgz", + "integrity": "sha512-aKUhyn1QI5Ksbqcr3fFJj16p99QdjUxXAEuFst1Z47DRyoiMwivIH9MV/ARcJOCXVjPfjITciej8ZD2O/6qUmw==", + "dependencies": { + "comment-parser": "1.4.1", + "esquery": "^1.5.0", + "jsdoc-type-pratt-parser": "~4.0.0" + }, + "engines": { + "node": ">=16" + } + }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", - "dev": true, "dependencies": { "eslint-visitor-keys": "^3.3.0" }, @@ -730,7 +748,6 @@ "version": "4.8.1", "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.8.1.tgz", "integrity": "sha512-PWiOzLIUAjN/w5K17PoF4n6sKBw0gqLHPhywmYHP4t1VFQQVYeb1yWsJwnMVEMl3tUHME7X/SJPZLmtG7XBDxQ==", - "dev": true, "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } @@ -739,7 +756,6 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.2.tgz", "integrity": "sha512-+wvgpDsrB1YqAMdEUCcnTlpfVBH7Vqn6A/NT3D8WVXFIaKMlErPIZT3oCIAVCOtarRpMtelZLqJeU3t7WY6X6g==", - "dev": true, "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", @@ -762,7 +778,6 @@ "version": "8.49.0", "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.49.0.tgz", "integrity": "sha512-1S8uAY/MTJqVx0SC4epBq+N2yhuwtNwLbJYNZyhL2pO1ZVKn5HFXav5T41Ryzy9K9V7ZId2JB2oy/W4aCd9/2w==", - "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } @@ -857,7 +872,6 @@ "version": "0.11.11", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.11.tgz", "integrity": "sha512-N2brEuAadi0CcdeMXUkhbZB84eskAc8MEX1By6qEchoVywSgXPIjou4rYsl0V3Hj0ZnuGycGCjdNgockbzeWNA==", - "dev": true, "dependencies": { "@humanwhocodes/object-schema": "^1.2.1", "debug": "^4.1.1", @@ -871,7 +885,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, "engines": { "node": ">=12.22" }, @@ -883,8 +896,7 @@ "node_modules/@humanwhocodes/object-schema": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", - "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", - "dev": true + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==" }, "node_modules/@istanbuljs/load-nyc-config": { "version": "1.1.0", @@ -1360,7 +1372,6 @@ "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" @@ -1373,7 +1384,6 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, "engines": { "node": ">= 8" } @@ -1382,7 +1392,6 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" @@ -1550,6 +1559,12 @@ "integrity": "sha512-LG4opVs2ANWZ1TJoKc937iMmNstM/d0ae1vNbnBvBhqCSezgVUOzcLCqbI5elV8Vy6WKwKjaqR+zO9VKirBBCA==", "dev": true }, + "node_modules/@types/expect": { + "version": "1.20.4", + "resolved": "https://registry.npmjs.org/@types/expect/-/expect-1.20.4.tgz", + "integrity": "sha512-Q5Vn3yjTDyCMV50TB6VRIbQNxSE4OmZR86VSbGaNpfUolm0iePBB4KdEEHmxoY5sT2+2DIvXW0rvMDP2nHZ4Mg==", + "dev": true + }, "node_modules/@types/fs-extra": { "version": "8.1.3", "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-8.1.3.tgz", @@ -1655,6 +1670,16 @@ "integrity": "sha512-THo502dA5PzG/sfQH+42Lw3fvmYkceefOspdCwpHRul8ik2Jv1K8I5OZz1AT3/rs46kwgMCe9bSBmDLYkkOMGg==", "dev": true }, + "node_modules/@types/vinyl": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/@types/vinyl/-/vinyl-2.0.11.tgz", + "integrity": "sha512-vPXzCLmRp74e9LsP8oltnWKTH+jBwt86WgRUb4Pc9Lf3pkMVGyvIo2gm9bODeGfCay2DBB/hAWDuvf07JcK4rw==", + "dev": true, + "dependencies": { + "@types/expect": "^1.20.4", + "@types/node": "*" + } + }, "node_modules/@types/yargs": { "version": "17.0.28", "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.28.tgz", @@ -1828,7 +1853,6 @@ "version": "8.10.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", - "dev": true, "bin": { "acorn": "bin/acorn" }, @@ -1850,7 +1874,6 @@ "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } @@ -1876,11 +1899,26 @@ "node": ">= 6.0.0" } }, + "node_modules/aggregate-error": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-4.0.1.tgz", + "integrity": "sha512-0poP0T7el6Vq3rstR8Mn4V/IQrpBLO6POkUSrN7RhyY+GF/InCFShQzsQ39T25gkHhLgSLByyAz+Kjb+c2L98w==", + "dev": true, + "dependencies": { + "clean-stack": "^4.0.0", + "indent-string": "^5.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -1947,7 +1985,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, "engines": { "node": ">=8" } @@ -1956,7 +1993,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -2007,11 +2043,18 @@ "integrity": "sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==", "dev": true }, + "node_modules/are-docs-informative": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/are-docs-informative/-/are-docs-informative-0.0.2.tgz", + "integrity": "sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==", + "engines": { + "node": ">=14" + } + }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" }, "node_modules/arr-diff": { "version": "4.0.0", @@ -2362,8 +2405,7 @@ "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" }, "node_modules/base": { "version": "0.11.2", @@ -2449,7 +2491,6 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -2508,6 +2549,15 @@ "node-int64": "^0.4.0" } }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "dev": true, + "engines": { + "node": "*" + } + }, "node_modules/buffer-equal": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-1.0.1.tgz", @@ -2530,7 +2580,6 @@ "version": "3.3.0", "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", - "dev": true, "engines": { "node": ">=6" }, @@ -2590,7 +2639,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, "engines": { "node": ">=6" } @@ -2628,7 +2676,6 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -2798,6 +2845,33 @@ "node": ">=0.10.0" } }, + "node_modules/clean-stack": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-4.2.0.tgz", + "integrity": "sha512-LYv6XPxoyODi36Dp976riBtSY27VmFo+MKqEU9QCCWyTrdEPDog+RWA7xQWHi6Vbp61j5c4cdzzX1NidnwtUWg==", + "dev": true, + "dependencies": { + "escape-string-regexp": "5.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/clean-stack/node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/cli-cursor": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-4.0.0.tgz", @@ -2980,7 +3054,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, "dependencies": { "color-name": "~1.1.4" }, @@ -2991,8 +3064,7 @@ "node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "node_modules/color-support": { "version": "1.1.3", @@ -3021,6 +3093,14 @@ "node": ">= 0.8" } }, + "node_modules/comment-parser": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.1.tgz", + "integrity": "sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==", + "engines": { + "node": ">= 12.0.0" + } + }, "node_modules/component-emitter": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", @@ -3030,8 +3110,7 @@ "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" }, "node_modules/concat-stream": { "version": "1.6.2", @@ -3109,11 +3188,28 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/cross-env": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", + "integrity": "sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.1" + }, + "bin": { + "cross-env": "src/bin/cross-env.js", + "cross-env-shell": "src/bin/cross-env-shell.js" + }, + "engines": { + "node": ">=10.14", + "npm": ">=6", + "yarn": ">=1" + } + }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -3186,7 +3282,6 @@ "version": "4.3.4", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "dev": true, "dependencies": { "ms": "2.1.2" }, @@ -3260,8 +3355,7 @@ "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==" }, "node_modules/deepmerge": { "version": "4.3.1", @@ -3383,6 +3477,71 @@ "node": ">=0.10.0" } }, + "node_modules/del": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/del/-/del-7.1.0.tgz", + "integrity": "sha512-v2KyNk7efxhlyHpjEvfyxaAihKKK0nWCuf6ZtqZcFFpQRG0bJ12Qsr0RpvsICMjAAZ8DOVCxrlqpxISlMHC4Kg==", + "dev": true, + "dependencies": { + "globby": "^13.1.2", + "graceful-fs": "^4.2.10", + "is-glob": "^4.0.3", + "is-path-cwd": "^3.0.0", + "is-path-inside": "^4.0.0", + "p-map": "^5.5.0", + "rimraf": "^3.0.2", + "slash": "^4.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/del/node_modules/globby": { + "version": "13.2.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-13.2.2.tgz", + "integrity": "sha512-Y1zNGV+pzQdh7H39l9zgB4PJqjRNqydvdYCDG4HFXM4XuvSaQQlEc91IU1yALL8gUTDomgBAfz3XJdmUS+oo0w==", + "dev": true, + "dependencies": { + "dir-glob": "^3.0.1", + "fast-glob": "^3.3.0", + "ignore": "^5.2.4", + "merge2": "^1.4.1", + "slash": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/del/node_modules/is-path-inside": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-4.0.0.tgz", + "integrity": "sha512-lJJV/5dYS+RcL8uQdBDW9c9uWFLLBNRyFhnAKXw5tVqLlKZ4RMGZKv+YQ/IA3OhD+RpbJa1LLFM1FQPGyIXvOA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/del/node_modules/slash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", + "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -3435,7 +3594,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, "dependencies": { "esutils": "^2.0.2" }, @@ -3495,6 +3653,18 @@ "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", "dev": true }, + "node_modules/easy-transform-stream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/easy-transform-stream/-/easy-transform-stream-1.0.1.tgz", + "integrity": "sha512-ktkaa6XR7COAR3oj02CF3IOgz2m1hCaY3SfzvKT4Svt2MhHw9XCt+ncJNWfe2TGz31iqzNGZ8spdKQflj+Rlog==", + "dev": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/electron-to-chromium": { "version": "1.4.523", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.523.tgz", @@ -3598,7 +3768,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, "engines": { "node": ">=10" }, @@ -3631,7 +3800,6 @@ "version": "8.49.0", "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.49.0.tgz", "integrity": "sha512-jw03ENfm6VJI0jA9U+8H5zfl5b+FvuU3YYvZRdZHOlU2ggJkxrlkJH4HcDrZpj6YwD8kuYqvQM8LyesoazrSOQ==", - "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", @@ -3718,6 +3886,37 @@ } } }, + "node_modules/eslint-plugin-jsdoc": { + "version": "46.9.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-46.9.1.tgz", + "integrity": "sha512-11Ox5LCl2wY7gGkp9UOyew70o9qvii1daAH+h/MFobRVRNcy7sVlH+jm0HQdgcvcru6285GvpjpUyoa051j03Q==", + "dependencies": { + "@es-joy/jsdoccomment": "~0.41.0", + "are-docs-informative": "^0.0.2", + "comment-parser": "1.4.1", + "debug": "^4.3.4", + "escape-string-regexp": "^4.0.0", + "esquery": "^1.5.0", + "is-builtin-module": "^3.2.1", + "semver": "^7.5.4", + "spdx-expression-parse": "^4.0.0" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + } + }, + "node_modules/eslint-plugin-jsdoc/node_modules/spdx-expression-parse": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-4.0.0.tgz", + "integrity": "sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, "node_modules/eslint-plugin-prettier": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.0.0.tgz", @@ -3751,7 +3950,6 @@ "version": "7.2.2", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", - "dev": true, "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" @@ -3767,7 +3965,6 @@ "version": "3.4.3", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, @@ -3779,7 +3976,6 @@ "version": "9.6.1", "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", - "dev": true, "dependencies": { "acorn": "^8.9.0", "acorn-jsx": "^5.3.2", @@ -3809,7 +4005,6 @@ "version": "1.5.0", "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", - "dev": true, "dependencies": { "estraverse": "^5.1.0" }, @@ -3821,7 +4016,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, "dependencies": { "estraverse": "^5.2.0" }, @@ -3833,7 +4027,6 @@ "version": "5.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, "engines": { "node": ">=4.0" } @@ -3848,7 +4041,6 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -4155,8 +4347,7 @@ "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, "node_modules/fast-diff": { "version": "1.3.0", @@ -4164,6 +4355,12 @@ "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", "dev": true }, + "node_modules/fast-fifo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", + "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==", + "dev": true + }, "node_modules/fast-glob": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz", @@ -4195,20 +4392,17 @@ "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" }, "node_modules/fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==" }, "node_modules/fastq": { "version": "1.15.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", - "dev": true, "dependencies": { "reusify": "^1.0.4" } @@ -4226,7 +4420,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, "dependencies": { "flat-cache": "^3.0.4" }, @@ -4257,7 +4450,6 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" @@ -4464,7 +4656,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.1.0.tgz", "integrity": "sha512-OHx4Qwrrt0E4jEIcI5/Xb+f+QmJYNj2rrK8wiIdQOIrB9WrrJL8cjZvXdXuBTkkEwEqLycb5BeZDV1o2i9bTew==", - "dev": true, "dependencies": { "flatted": "^3.2.7", "keyv": "^4.5.3", @@ -4477,8 +4668,7 @@ "node_modules/flatted": { "version": "3.2.9", "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", - "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", - "dev": true + "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==" }, "node_modules/flush-write-stream": { "version": "1.1.1", @@ -4567,8 +4757,7 @@ "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" }, "node_modules/fsevents": { "version": "2.3.3", @@ -4657,7 +4846,6 @@ "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -4677,7 +4865,6 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, "dependencies": { "is-glob": "^4.0.3" }, @@ -5052,7 +5239,6 @@ "version": "13.21.0", "resolved": "https://registry.npmjs.org/globals/-/globals-13.21.0.tgz", "integrity": "sha512-ybyme3s4yy/t/3s35bewwXKOf7cvzfreG2lH0lZl0JB7I4GxRP2ghxOK/Nb9EkRXdbBXZLfq/p/0W2JUONB/Gg==", - "dev": true, "dependencies": { "type-fest": "^0.20.2" }, @@ -5115,8 +5301,7 @@ "node_modules/graphemer": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==" }, "node_modules/gulp": { "version": "4.0.2", @@ -5402,6 +5587,35 @@ "node": ">=4" } }, + "node_modules/gulp-plugin-extras": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/gulp-plugin-extras/-/gulp-plugin-extras-0.3.0.tgz", + "integrity": "sha512-I/kOBSpo61QsGQZcqozZYEnDseKvpudUafVVWDLYgBFAUJ37kW5R8Sjw9cMYzpGyPUfEYOeoY4p+dkfLqgyJUQ==", + "dev": true, + "dependencies": { + "@types/vinyl": "^2.0.9", + "chalk": "^5.3.0", + "easy-transform-stream": "^1.0.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gulp-plugin-extras/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "dev": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/gulp-sourcemaps": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/gulp-sourcemaps/-/gulp-sourcemaps-3.0.0.tgz", @@ -5436,6 +5650,69 @@ "node": ">=0.4.0" } }, + "node_modules/gulp-zip": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/gulp-zip/-/gulp-zip-6.0.0.tgz", + "integrity": "sha512-fPGvNve2dBoZxGKcviTU7mOa77eQibyhwgGLTxnF+ZCKX8RFaTZKkPbdPnmw0r4TNPRjPCkQB/0VuP+MzgkEYg==", + "dev": true, + "dependencies": { + "get-stream": "^8.0.1", + "gulp-plugin-extras": "^0.3.0", + "vinyl": "^3.0.0", + "yazl": "^2.5.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + }, + "peerDependencies": { + "gulp": ">=4" + }, + "peerDependenciesMeta": { + "gulp": { + "optional": true + } + } + }, + "node_modules/gulp-zip/node_modules/get-stream": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", + "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", + "dev": true, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gulp-zip/node_modules/replace-ext": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-2.0.0.tgz", + "integrity": "sha512-UszKE5KVK6JvyD92nzMn9cDapSk6w/CaFZ96CnmDMUqH9oowfxF/ZjRITD25H4DnOQClLA4/j7jLGXXLVKxAug==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/gulp-zip/node_modules/vinyl": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-3.0.0.tgz", + "integrity": "sha512-rC2VRfAVVCGEgjnxHUnpIVh3AGuk62rP3tqVrn+yab0YH7UULisC085+NYH+mnqf3Wx4SpSi1RQMwudL89N03g==", + "dev": true, + "dependencies": { + "clone": "^2.1.2", + "clone-stats": "^1.0.0", + "remove-trailing-separator": "^1.1.0", + "replace-ext": "^2.0.0", + "teex": "^1.0.1" + }, + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/gulplog": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/gulplog/-/gulplog-1.0.0.tgz", @@ -5464,7 +5741,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, "engines": { "node": ">=8" } @@ -5671,7 +5947,6 @@ "version": "5.2.4", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", - "dev": true, "engines": { "node": ">= 4" } @@ -5686,7 +5961,6 @@ "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" @@ -5721,16 +5995,26 @@ "version": "0.1.4", "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, "engines": { "node": ">=0.8.19" } }, + "node_modules/indent-string": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-5.0.0.tgz", + "integrity": "sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dev": true, "dependencies": { "once": "^1.3.0", "wrappy": "1" @@ -5739,8 +6023,7 @@ "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "node_modules/ini": { "version": "1.3.8", @@ -5828,7 +6111,6 @@ "version": "3.2.1", "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz", "integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==", - "dev": true, "dependencies": { "builtin-modules": "^3.3.0" }, @@ -5938,7 +6220,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -5968,7 +6249,6 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, "dependencies": { "is-extglob": "^2.1.1" }, @@ -6018,11 +6298,22 @@ "node": ">=0.12.0" } }, + "node_modules/is-path-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-3.0.0.tgz", + "integrity": "sha512-kyiNFFLU0Ampr6SDZitD/DwUo4Zs1nSdnygUBqsu3LooL00Qvb5j+UnvApUn/TTj1J3OuE6BTdQ5rudKmU2ZaA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-path-inside": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, "engines": { "node": ">=8" } @@ -6144,8 +6435,7 @@ "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" }, "node_modules/isobject": { "version": "3.0.1", @@ -6967,7 +7257,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, "dependencies": { "argparse": "^2.0.1" }, @@ -6975,6 +7264,14 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/jsdoc-type-pratt-parser": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-4.0.0.tgz", + "integrity": "sha512-YtOli5Cmzy3q4dP26GraSOeAhqecewG04hoO8DY56CH4KJ9Fvv5qKWUCCo3HZob7esJQHCv6/+bnTy72xZZaVQ==", + "engines": { + "node": ">=12.0.0" + } + }, "node_modules/jsdom": { "version": "20.0.3", "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-20.0.3.tgz", @@ -7035,8 +7332,7 @@ "node_modules/json-buffer": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==" }, "node_modules/json-parse-even-better-errors": { "version": "2.3.1", @@ -7047,14 +7343,12 @@ "node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==" }, "node_modules/json5": { "version": "2.2.3", @@ -7090,7 +7384,6 @@ "version": "4.5.3", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.3.tgz", "integrity": "sha512-QCiSav9WaX1PgETJ+SpNnx2PRRapJ/oRSXM4VO5OGYGSjrxbKPVFVhB3l2OCbLCk329N8qyAtsJjSjvVBWzEug==", - "dev": true, "dependencies": { "json-buffer": "3.0.1" } @@ -7175,7 +7468,6 @@ "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" @@ -7377,7 +7669,6 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, "dependencies": { "p-locate": "^5.0.0" }, @@ -7397,8 +7688,7 @@ "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" }, "node_modules/log-update": { "version": "5.0.1", @@ -7819,7 +8109,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, "dependencies": { "brace-expansion": "^1.1.7" }, @@ -7855,8 +8144,7 @@ "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/mute-stdout": { "version": "1.0.1", @@ -7908,8 +8196,7 @@ "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==" }, "node_modules/next-tick": { "version": "1.1.0", @@ -8203,7 +8490,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, "dependencies": { "wrappy": "1" } @@ -8245,7 +8531,6 @@ "version": "0.9.3", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", - "dev": true, "dependencies": { "@aashutoshrathi/word-wrap": "^1.2.3", "deep-is": "^0.1.3", @@ -8283,7 +8568,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, "dependencies": { "yocto-queue": "^0.1.0" }, @@ -8298,7 +8582,6 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, "dependencies": { "p-limit": "^3.0.2" }, @@ -8309,6 +8592,21 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/p-map": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-5.5.0.tgz", + "integrity": "sha512-VFqfGDHlx87K66yZrNdI4YGtD70IRyd+zSvgks6mzHPRNkoKy+9EKP4SFC77/vTTQYmRmti7dvqC+m5jBrBAcg==", + "dev": true, + "dependencies": { + "aggregate-error": "^4.0.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/p-try": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", @@ -8322,7 +8620,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, "dependencies": { "callsites": "^3.0.0" }, @@ -8423,7 +8720,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, "engines": { "node": ">=8" } @@ -8432,7 +8728,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -8441,7 +8736,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, "engines": { "node": ">=8" } @@ -8634,7 +8928,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, "engines": { "node": ">= 0.8.0" } @@ -8751,7 +9044,6 @@ "version": "2.3.0", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", - "dev": true, "engines": { "node": ">=6" } @@ -8782,7 +9074,6 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, "funding": [ { "type": "github", @@ -8798,6 +9089,12 @@ } ] }, + "node_modules/queue-tick": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz", + "integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==", + "dev": true + }, "node_modules/react-is": { "version": "18.2.0", "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", @@ -9087,7 +9384,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, "engines": { "node": ">=4" } @@ -9173,7 +9469,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, "engines": { "iojs": ">=1.0.0", "node": ">=0.10.0" @@ -9189,7 +9484,6 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, "dependencies": { "glob": "^7.1.3" }, @@ -9371,7 +9665,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, "funding": [ { "type": "github", @@ -9458,7 +9751,6 @@ "version": "7.5.4", "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, "dependencies": { "lru-cache": "^6.0.0" }, @@ -9485,7 +9777,6 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, "dependencies": { "yallist": "^4.0.0" }, @@ -9496,8 +9787,7 @@ "node_modules/semver/node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/set-blocking": { "version": "2.0.0", @@ -9557,7 +9847,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, "dependencies": { "shebang-regex": "^3.0.0" }, @@ -9569,7 +9858,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, "engines": { "node": ">=8" } @@ -9883,8 +10171,7 @@ "node_modules/spdx-exceptions": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", - "dev": true + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==" }, "node_modules/spdx-expression-parse": { "version": "3.0.1", @@ -9899,8 +10186,7 @@ "node_modules/spdx-license-ids": { "version": "3.0.16", "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.16.tgz", - "integrity": "sha512-eWN+LnM3GR6gPu35WxNgbGl8rmY1AEmoMDvL/QD6zYmPWgywxWqJWNdLGT+ke8dKNWrcYgYjPpG5gbTfghP8rw==", - "dev": true + "integrity": "sha512-eWN+LnM3GR6gPu35WxNgbGl8rmY1AEmoMDvL/QD6zYmPWgywxWqJWNdLGT+ke8dKNWrcYgYjPpG5gbTfghP8rw==" }, "node_modules/split-string": { "version": "3.1.0", @@ -10049,6 +10335,16 @@ "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==", "dev": true }, + "node_modules/streamx": { + "version": "2.15.6", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.15.6.tgz", + "integrity": "sha512-q+vQL4AAz+FdfT137VF69Cc/APqUbxy+MDOImRrMvchJpigHj9GksgDU2LYbO9rx7RX6osWgxJB2WxhYv4SZAw==", + "dev": true, + "dependencies": { + "fast-fifo": "^1.1.0", + "queue-tick": "^1.0.1" + } + }, "node_modules/string_decoder": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", @@ -10134,7 +10430,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -10176,7 +10471,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, "engines": { "node": ">=8" }, @@ -10188,7 +10482,6 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, "dependencies": { "has-flag": "^4.0.0" }, @@ -10240,6 +10533,15 @@ "url": "https://opencollective.com/unts" } }, + "node_modules/teex": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/teex/-/teex-1.0.1.tgz", + "integrity": "sha512-eYE6iEI62Ni1H8oIa7KlDU6uQBtqr4Eajni3wX7rpfXD8ysFx8z0+dri+KWEPWpBsxXfxu58x/0jvTVT1ekOSg==", + "dev": true, + "dependencies": { + "streamx": "^2.12.5" + } + }, "node_modules/test-exclude": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", @@ -10257,8 +10559,7 @@ "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==" }, "node_modules/through2": { "version": "2.0.5", @@ -10475,7 +10776,6 @@ "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, "dependencies": { "prelude-ls": "^1.2.1" }, @@ -10496,7 +10796,6 @@ "version": "0.20.2", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, "engines": { "node": ">=10" }, @@ -10511,11 +10810,9 @@ "dev": true }, "node_modules/typescript": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", - "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", - "dev": true, - "peer": true, + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", + "integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -10713,7 +11010,6 @@ "version": "4.4.1", "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, "dependencies": { "punycode": "^2.1.0" } @@ -10991,7 +11287,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, "dependencies": { "isexe": "^2.0.0" }, @@ -11067,8 +11362,7 @@ "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, "node_modules/write-file-atomic": { "version": "4.0.2", @@ -11205,11 +11499,19 @@ "node": ">=8" } }, + "node_modules/yazl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/yazl/-/yazl-2.5.1.tgz", + "integrity": "sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw==", + "dev": true, + "dependencies": { + "buffer-crc32": "~0.2.3" + } + }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, "engines": { "node": ">=10" }, diff --git a/package.json b/package.json index 188c25e..b800ed4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "theater-of-the-mind", - "version": "1.4.7", + "version": "2.0.0", "description": "A FoundryVTT module for DMs", "main": "index.js", "author": { @@ -24,22 +24,25 @@ "scripts": { "build": "gulp build", "build:watch": "gulp watch", + "devexport": "gulp devexport", "link-project": "gulp link", "clean": "gulp clean", "clean:link": "gulp link --clean", "lint": "eslint --ext .js,.cjs,.mjs .", "lint:fix": "eslint --ext .js,.cjs,.mjs --fix .", "format": "prettier --write \"./**/*.(js|cjs|mjs|json|yml|scss)\"", - "test": "jest", - "test:watch": "jest --watch", - "test:ci": "jest --ci --reporters=default --reporters=jest-junit", + "test": "cross-env NODE_OPTIONS=--experimental-vm-modules jest", + "test:watch": "cross-env NODE_OPTIONS=--experimental-vm-modules jest --watch", + "test:ci": "cross-env NODE_OPTIONS=--experimental-vm-modules jest --ci --reporters=default --reporters=jest-junit", "postinstall": "husky install", - "changelog2": "generate-changelog -u 'https://github.com/EddieDover/theater-of-the-mind'" + "changelog2": "generate-changelog -u https://github.com/EddieDover/theater-of-the-mind" }, "devDependencies": { "@rollup/plugin-node-resolve": "^15.2.1", "@rollup/stream": "^3.0.0", "@typhonjs-fvtt/eslint-config-foundry.js": "^0.8.0", + "cross-env": "^7.0.3", + "del": "^7.1.0", "eslint": "^8.49.0", "eslint-config-prettier": "^9.0.0", "eslint-plugin-jest": "^27.4.2", @@ -48,6 +51,7 @@ "gulp": "^4.0.2", "gulp-dart-sass": "^1.1.0", "gulp-sourcemaps": "^3.0.0", + "gulp-zip": "^6.0.0", "husky": "^8.0.3", "jest": "^29.7.0", "jest-environment-jsdom": "^29.7.0", @@ -63,5 +67,9 @@ "lint-staged": { "*.(js|cjs|mjs)": "eslint --fix", "*.(json|yml|scss)": "prettier --write" + }, + "dependencies": { + "eslint-plugin-jsdoc": "^46.9.1", + "typescript": "^5.3.3" } -} +} \ No newline at end of file diff --git a/rollup.config.mjs b/rollup.config.mjs index 199af90..77f611f 100644 --- a/rollup.config.mjs +++ b/rollup.config.mjs @@ -2,22 +2,23 @@ // SPDX-FileCopyrightText: 2022 David Archibald // // SPDX-License-Identifier: MIT -import copy from 'rollup-plugin-copy' -import { nodeResolve } from '@rollup/plugin-node-resolve'; +import copy from "rollup-plugin-copy"; +import { nodeResolve } from "@rollup/plugin-node-resolve"; export default () => ({ - input: 'src/module/theater-of-the-mind.js', + input: "src/module/theater-of-the-mind.js", output: { - dir: 'dist/module', - format: 'es', + dir: "dist/module", + format: "es", sourcemap: true, }, plugins: [ nodeResolve(), copy({ targets: [ - { src: 'CHANGELOG.md', dest: 'dist' }, - ] - }) + { src: "*.md", dest: "dist" }, + { src: "example_templates/*", dest: "dist/example_templates" }, + ], + }), ], }); diff --git a/src/lang/en.json b/src/lang/en.json index 2da7d53..1f086e7 100644 --- a/src/lang/en.json +++ b/src/lang/en.json @@ -5,7 +5,11 @@ "race": "Race", "senses": "Senses", "classes": "Classes", - "no-players": "No players are currently logged in." + "no-players": "No players are currently logged in.", + "no-systems": "You do not have any json files for this sytem in your data/totm folder. Please add some to enable this feature.", + "bugreport": "File a Bug Report", + "feedback": "Send Feedback", + "discord": "Discord" }, "hide-sheet": { "button": "Configure Hidden Characters", @@ -17,14 +21,18 @@ "name": "Show only online characters", "hint": "Only show characters assigned to logged in players. Turning this off will show all non-NPC characters but allow you to 'hide' the ones you don't care about." }, - "enable-sounds": { + "enable-sounds": { "name": "Enable Syrinscape Sounds", "hint": "Sound support requires the Syrinscape Integration (fvtt-synrin-control) and Midi QOL (midi-qol) modules." }, - "enable-dark-mode": { + "enable-dark-mode": { "name": "Enable Dark Mode", "hint": "Enable dark mode for the party sheet." - } + }, + "show-debug-info": { + "name": "Show Debug Information", + "hint": "Enable this to show debug information in the console for all parsed characters when the party sheet is opened. Hopefully this will allow you to track down specific properties that you are trying to parse." + } } } } diff --git a/src/lang/es.json b/src/lang/es.json index 7f3b598..9faa7a2 100644 --- a/src/lang/es.json +++ b/src/lang/es.json @@ -5,7 +5,11 @@ "race": "Raza", "senses": "Sentidos", "classes": "Clases", - "no-players": "Ningún jugador ha iniciado sesión actualmente." + "no-players": "Ningún jugador ha iniciado sesión actualmente.", + "no-systems": "La carpeta data/totm no contiene archivos JSON para este sistema. Necesitas agregar algunos para activar esta funcionalidad.", + "bugreport": "Dar retroalimentación", + "feedback": "Reportar un fallo", + "discord": "Discord" }, "hide-sheet":{ "button": "Configurar personajes ocultos", @@ -20,11 +24,15 @@ "enable-sounds": { "name": "Habilitar Sonidos de Syrinscape", "hint": "El soporte de sonido requiere los módulos Syrinscape Integration (fvtt-synrin-control) y Midi QOL (midi-qol)." - }, - "enable-dark-mode": { - "name": "Habilitar el modo oscuro", - "hint": "Habilitar la hoja de fiesta en modo oscuro." - } + }, + "enable-dark-mode": { + "name": "Habilitar el modo oscuro", + "hint": "Habilitar la hoja de fiesta en modo oscuro." + }, + "show-debug-info": { + "name":"Mostrar información de depuración", + "hint": "Actívelo para mostrar información de depuración en la consola para todos los personajes analizados cuando se abre la hoja de grupo. Esperemos que esto le permita rastrear propiedades específicas que está intentando analizar." + } } } } diff --git a/src/module.json b/src/module.json index effc4e0..a458450 100644 --- a/src/module.json +++ b/src/module.json @@ -1,68 +1,63 @@ { - "id": "theater-of-the-mind", - "title": "Theater of the Mind - DM Tool", - "description": "A module to assist DMs who run theater of the mind adventures.", - "url": "https://github.com/EddieDover/theater-of-the-mind", - "bugs": "https://github.com/EddieDover/theater-of-the-mind/issues", - "changelog": "https://github.com/EddieDover/theater-of-the-mind/releases", - "manifest": "https://github.com/EddieDover/theater-of-the-mind/releases/latest/download/module.json", - "download": "https://github.com/EddieDover/theater-of-the-mind/releases/latest/download/module.zip", - "license": "https://github.com/EddieDover/theater-of-the-mind/raw/main/LICENSE.md", - "readme": "https://github.com/EddieDover/theater-of-the-mind/raw/main/README.md", - "flags": { - "allowBugReporter": true + "id": "theater-of-the-mind", + "title": "Theater of the Mind - DM Tool", + "description": "This system agnostic module will provide a GM with a 'party view' feature similar to that of Fantasy Grounds, online characters only, or all characters, configurable in settings, in order to quickly see important stats, traits, abilites, etc. It's a great tool for GMs running token/map games or Theater of the Mind style games.", + "url": "https://github.com/EddieDover/theater-of-the-mind", + "bugs": "https://github.com/EddieDover/theater-of-the-mind/issues", + "changelog": "https://github.com/EddieDover/theater-of-the-mind/releases", + "manifest": "https://github.com/EddieDover/theater-of-the-mind/releases/latest/download/module.json", + "download": "https://github.com/EddieDover/theater-of-the-mind/releases/latest/download/module.zip", + "license": "https://github.com/EddieDover/theater-of-the-mind/raw/main/LICENSE.md", + "readme": "https://github.com/EddieDover/theater-of-the-mind/raw/main/README.md", + "flags": { + "allowBugReporter": true + }, + "languages": [ + { + "lang": "en", + "name": "English", + "path": "lang/en.json" }, - "languages": [ - { - "lang": "en", - "name": "English", - "path": "lang/en.json" - }, - { - "lang": "es", - "name": "Spanish", - "path": "lang/es.json" - } - ], + { + "lang": "es", + "name": "Spanish", + "path": "lang/es.json" + } + ], "media": [ - { - "type": "cover", - "url": "" - } + { + "type": "cover", + "url": "" + } ], - "authors": [ + "authors": [ + { + "name": "Eddie Dover", + "email": "ed@eddiedover.dev", + "url": "https://github.com/eddiedover/" + } + ], + "version": "2.0.0", + "compatibility": { + "minimum": "11", + "verified": "11" + }, + "esmodules": [ + "module/theater-of-the-mind.js" + ], + "styles": [ + "styles/theater-of-the-mind.css" + ], + "relationships": { + "optional": [ { - "name": "Eddie Dover", - "email": "ed@eddiedover.dev", - "url": "https://github.com/eddiedover/" + "id": "midi-qol", + "type": "module" + }, + { + "id": "fvtt-syrin-control", + "type": "module" } - ], - "version": "1.4.7", - "compatibility": { - "minimum": "11", - "verified": "11" - }, - "esmodules": [ - "module/theater-of-the-mind.js" - ], - "styles": ["styles/theater-of-the-mind.css"], - "relationships": { - "optional": [ - { - "id": "midi-qol", "type": "module" - }, - { - "id": "fvtt-syrin-control", "type":"module" - } - ], - "systems": [ - { - "id": "dnd5e", - "type": "system", - "compatibility": { - "minimum": "2.0.0" - } - } - ] - } + ] } +} \ No newline at end of file diff --git a/src/module/app/hidden-characters-settings.js b/src/module/app/hidden-characters-settings.js index c583dc9..7893fcd 100644 --- a/src/module/app/hidden-characters-settings.js +++ b/src/module/app/hidden-characters-settings.js @@ -1,4 +1,5 @@ /* eslint-disable no-undef */ +// @ts-ignore export class HiddenCharactersSettings extends FormApplication { constructor(overrides) { super(); @@ -6,14 +7,18 @@ export class HiddenCharactersSettings extends FormApplication { } getData(options) { + // @ts-ignore this.characterList = game.actors .filter((actor) => actor.type !== "npc") .map((actor) => { return { "uuid": actor.uuid, "name": actor.name }; }); + // @ts-ignore const hiddenCharacters = game.settings.get("theater-of-the-mind", "hiddenCharacters"); + // @ts-ignore const enableOnlyOnline = game.settings.get("theater-of-the-mind", "enableOnlyOnline"); + // @ts-ignore return mergeObject(super.getData(options), { characters: this.characterList, hiddenCharacters, @@ -23,13 +28,16 @@ export class HiddenCharactersSettings extends FormApplication { } static get defaultOptions() { + // @ts-ignore return foundry.utils.mergeObject(super.defaultOptions, { id: "totm-hidden-characters-settings", classes: ["form"], title: "Configure Hidden Characters", + // resizable: true, template: "modules/theater-of-the-mind/templates/hidden-characters.hbs", - width: "auto", - height: 300, + // @ts-ignore + width: "auto", // $(window).width() > 960 ? 960 : $(window).width() - 100, + height: "auto", }); } @@ -37,10 +45,12 @@ export class HiddenCharactersSettings extends FormApplication { const hiddenCharacters = []; for (const character of this.characterList) { const checkbox = document.getElementById(`hidden-character-${character.uuid}`); + // @ts-ignore if (checkbox.checked) { hiddenCharacters.push(character.uuid); } } + // @ts-ignore game.settings.set("theater-of-the-mind", "hiddenCharacters", hiddenCharacters); const closefunc = this.overrides?.onexit; if (closefunc) { @@ -51,12 +61,15 @@ export class HiddenCharactersSettings extends FormApplication { resetEffects() { // this.effects = game.settings.settings.get('monks-little-details.additional-effects').default; + // @ts-ignore this.refresh(); } activateListeners(html) { super.activateListeners(html); + // @ts-ignore $('button[name="submit"]', html).click(this.saveHiddenCharacters.bind(this)); + // @ts-ignore $('button[name="reset"]', html).click(this.resetEffects.bind(this)); } } diff --git a/src/module/app/party-sheet.js b/src/module/app/party-sheet.js index 8d6ce50..dcac9d4 100644 --- a/src/module/app/party-sheet.js +++ b/src/module/app/party-sheet.js @@ -1,74 +1,370 @@ /* eslint-disable no-undef */ +import { + extractPropertyByString, + getCustomSystems, + getSelectedSystem, + parsePluses, + trimIfString, + updateSelectedSystem, +} from "../utils.js"; import { HiddenCharactersSettings } from "./hidden-characters-settings.js"; +const FEEDBACK_URL = "https://github.com/eddiedover/theater-of-the-mind/issues/new?template=feature_request.md"; +const BUGREPORT_URL = "https://github.com/eddiedover/theater-of-the-mind/issues/new?template=bug_report.md"; +const DISCORD_URL = "https://discord.gg/XuGx7zNMKZ"; + +const NEWLINE_ELEMENTS = ["{newline}", "{nl}", ";"]; +const DEFAULT_EXCLUDES = ["npc"]; +// @ts-ignore export class PartySheetForm extends FormApplication { constructor() { super(); } - getPlayerData() { - const showOnlyOnlineUsers = game.settings.get("theater-of-the-mind", "enableOnlyOnline"); - const actorList = showOnlyOnlineUsers - ? game.users.filter((user) => user.active && user.character).map((user) => user.character) - : game.actors.filter((actor) => actor.type !== "npc"); + /** + * @typedef { 'direct' | 'math' | 'direct-complex' | 'string' | 'array-string-builder' } SystemDataColumnType + * @typedef { 'show' | 'hide' | 'skip' } SystemDataColumnHeader + * @typedef { 'left' | 'center' | 'right' } SystemDataColumnAlignType + * @typedef { 'top' | 'bottom' } SystemDataColumnVAlignType + */ - try { - return actorList - .map((character) => { - const userChar = character; - const userSys = userChar.system; - const stats = userSys.abilities; + /** + * @typedef SystemDataColumn + * @property {string} name - The name of the column. + * @property {SystemDataColumnType} type - The type of data to display. See below for details. + * @property {SystemDataColumnHeader} header - Whether to show, hide, or skip the column. + * @property {SystemDataColumnAlignType} align - The horizontal alignment of the column. + * @property {SystemDataColumnVAlignType} valign - The vertical alignment of the column. + * @property {number} colspan - The number of columns to span. + * @property {number} maxwidth - The maximum width of the column in pixels. + * @property {number} minwidth - The minimum width of the column in pixels. + * @property {string} text - The value to display. See below for details. + */ - const ac = userSys.attributes.ac.value; + /** + * @typedef ColOptions + * @property {SystemDataColumnHeader} header - Whether to show, hide, or skip the column. + * @property {SystemDataColumnAlignType} align - The horizontal alignment of the column. + * @property {SystemDataColumnVAlignType} valign - The vertical alignment of the column. + * @property {number} colspan - The number of columns to span. + * @property {number} maxwidth - The maximum width of the column in pixels. + * @property {number} minwidth - The minimum width of the column in pixels. + */ - const passives = { - prc: userSys.skills.prc.passive, - inv: userSys.skills.inv.passive, - ins: userSys.skills.ins.passive, - }; + /** + * @typedef SystemData + * @property { string } system - The system this data is for. + * @property { string } author - The author of this data. + * @property { string } name - The name of this data. + * @property { Array> } rows - The rows of data to display. See below for details. + * @property { string } offline_excludes_property - The property to use to exclude players. Note: This is optional and defaults to the actors.type property. + * @property { Array } offline_excludes - The types you want to exclude when showing offline players. + * @property { string } offline_includes_property - The property to use to show players online. + * @property { Array } offline_includes - The types you want to include when showing online players. + */ - const classNamesAndLevels = Object.values(userChar.classes).map((c) => `${c.name} ${c.system.levels}`); + /** + * @typedef { {name: string, author: string, players: any, rowcount: number} } CustomPlayerData + */ - const charToken = userChar.prototypeToken; + /** + * Get the custom player data. + * @param { SystemData } data - The system data + * @returns { CustomPlayerData } The custom player data + * @memberof PartySheetForm + */ - const charSenses = []; - if (userSys.attributes.senses.darkvision) { - charSenses.push(`Darkvision ${userSys.attributes.senses.darkvision} ${userSys.attributes.senses.units}`); - } - if (userSys.attributes.senses.blindsight) { - charSenses.push(`Blindsight ${userSys.attributes.senses.blindsight} ${userSys.attributes.senses.units}`); - } - if (userSys.attributes.senses.tremorsense) { - charSenses.push(`Tremorsense ${userSys.attributes.senses.tremorsense} ${userSys.attributes.senses.units}`); + getCustomPlayerData(data) { + //@ts-ignore + const showDebugOutput = game.settings.get("theater-of-the-mind", "showDebugInfo"); + const excludeTypes = data?.offline_excludes ? data.offline_excludes : DEFAULT_EXCLUDES; + + if (!data) { + return { name: "", author: "", players: [], rowcount: 0 }; + } + + // @ts-ignore + const showOnlyOnlineUsers = game.settings.get("theater-of-the-mind", "enableOnlyOnline"); + // @ts-ignore + const hiddenCharacters = game.settings.get("theater-of-the-mind", "hiddenCharacters"); + + if (showDebugOutput) { + console.log("======= TOTM DEBUG ACTORS LIST ======= "); + console.log( + "These are all the actors in your game. They have not yet been filtered based on your inclusions/exclusions.", + ); + } + + let actorList = showOnlyOnlineUsers + ? // @ts-ignore + game.users.filter((user) => user.active && user.character).map((user) => user.character) + : // @ts-ignore + game.actors.filter((actor) => { + // @ts-ignore + if (game.settings.get("theater-of-the-mind", "showDebugInfo")) { + console.log(actor); } - if (userSys.attributes.senses.truesight) { - charSenses.push(`Truesight ${userSys.attributes.senses.truesight} ${userSys.attributes.senses.units}`); + if (data.offline_includes_property && data.offline_includes) { + var propval = extractPropertyByString(actor, data.offline_includes_property); + return data.offline_includes.includes(propval); + } else if (excludeTypes) { + var incpropval = actor.type; + if (data.offline_excludes_property) { + incpropval = extractPropertyByString(actor, data.offline_excludes_property); + } + return !excludeTypes.includes(incpropval); } - if (userSys.attributes.senses.special) { - charSenses.push(userSys.attributes.senses.special); + }); + + if (showDebugOutput) { + console.log("====================================== "); + } + + if (!showOnlyOnlineUsers) { + actorList = actorList.filter((player) => !hiddenCharacters.includes(player.uuid)); + } + + try { + if (showDebugOutput) { + console.log("======= TOTM DEBUG CHARACTER LIST ======= "); + console.log("These are all the actors your party sheet will display."); + } + var finalActorList = actorList + .map((character) => { + const userChar = character; + + // @ts-ignore + if (game.settings.get("theater-of-the-mind", "showDebugInfo")) { + console.log(userChar); } - return { - name: userChar.name, - race: userChar.system.details.race, - uuid: userChar.uuid, - img: ``, - senses: charSenses.join(", "), - classNames: classNamesAndLevels.join(" - ") || "", - stats, - ac, - passives, - }; + var row_data = []; + + data.rows.map((row_obj) => { + var customData = {}; + + row_obj.forEach((colobj) => { + var colname = colobj.name; + customData[colname] = { + text: this.getCustomData(userChar, colobj.type, colobj.text), + options: { + align: colobj.align, + valign: colobj.valign, + colspan: colobj.colspan, + maxwidth: colobj.maxwidth, + minwidth: colobj.minwidth, + header: colobj.header, + }, + }; + }); + row_data.push(customData); + }); + + return row_data; }) .filter((player) => player); + if (showDebugOutput) { + console.log("========================================= "); + } + return { name: data.name, author: data.author, players: finalActorList, rowcount: data.rows.length }; } catch (ex) { console.log(ex); } - return []; + return { name: "", author: "", players: [], rowcount: 0 }; + } + + /** + * Clean a string of html injection. + * @param {string} str - The string to clean + * @returns {string} The cleaned string + * @memberof PartySheetForm + */ + cleanString(str) { + return str.replaceAll("&", "&").replaceAll("<", "<").replaceAll(">", ">"); + } + + /** + * Parse a direct string. + * @param {*} character - The character to parse + * @param {*} value - The value to parse + * @returns {[boolean, string]} Whether a safe string is needed and the value + */ + parseDirect(character, value) { + var isSafeStringNeeded = false; + + value = this.cleanString(value); + + //Parse out normal data + for (const m of value.split(" ")) { + var fvalue = extractPropertyByString(character, m); + if (fvalue !== undefined) { + value = value.replace(m, fvalue); + } + } + + //Parse out newline elements + for (const item of NEWLINE_ELEMENTS) { + if (value.indexOf(item) > -1) { + isSafeStringNeeded = true; + value = value.replaceAll(item, ""); + } + } + + //Parse out complex elements (that might contain newline elements we don't want to convert, like ; marks) + if (value.indexOf("{charactersheet}") > -1) { + isSafeStringNeeded = true; + value = value.replaceAll( + "{charactersheet}", + ``, + ); + // value = "" + value + ""; + } + + value = parsePluses(value); + + return [isSafeStringNeeded, value]; + } + + /** + * Get the custom data for a character. + * @param {*} character - The character to get the data for + * @param {*} type - The type of data to get + * @param {*} value - The value to get + * @returns {string} The text to render + * @memberof PartySheetForm + */ + getCustomData(character, type, value) { + var objName = ""; + var outstr = ""; + + /** @type {any} */ + var objData = {}; + var isSafeStringNeeded = false; + + //Prevent html injections! + switch (type) { + case "direct": + [isSafeStringNeeded, value] = this.parseDirect(character, value); + + //Finally detect if a safe string cast is needed. + if (isSafeStringNeeded) { + // @ts-ignore + return new Handlebars.SafeString(value); + } + return value; + case "direct-complex": + // Call .trim() on item.value but only if it's a string + var outputText = ""; + for (var item of value) { + item = trimIfString(item); + if (item.type === "exists") { + var evalue = extractPropertyByString(character, item.value); + if (evalue) { + outputText += item.text.replaceAll(item.value, evalue); + } else { + if (item.else) { + var nvalue = extractPropertyByString(character, item.else); + if (nvalue) { + outputText += nvalue; + } else { + outputText += item.else; + } + } + } + } else if (item.type === "match") { + var mvalue = extractPropertyByString(character, item.ifdata); + var match_value = extractPropertyByString(character, item.matches) ?? item.matches; + if (mvalue === match_value) { + outputText += extractPropertyByString(character, item.text) ?? item.text; + } else { + if (item.else) { + var mnvalue = extractPropertyByString(character, item.else); + if (mnvalue) { + outputText += mnvalue; + } else { + outputText += item.else; + } + } + } + } else if (item.type === "match-any") { + var mavalues = (Array.isArray(item.text) ? item.text : [item.text]).map((val) => + extractPropertyByString(character, val), + ); + var maatch_value = extractPropertyByString(character, item.match) ?? item.match; + + for (const maval of mavalues) { + if (maval === maatch_value) { + outputText += extractPropertyByString(character, item.text) ?? item.text; + } else { + if (item.else) { + var manvalue = extractPropertyByString(character, item.else); + if (manvalue) { + outputText += manvalue; + } else { + outputText += item.else; + } + } + } + } + } + } + // outputText = this.cleanString(outputText); + //return outputText; + [isSafeStringNeeded, outputText] = this.parseDirect(character, outputText); + // @ts-ignore + return isSafeStringNeeded ? new Handlebars.SafeString(outputText) : outputText; + + //regex match properties as [a-z][A-Z].*? + case "charactersheet": + // @ts-ignore + return new Handlebars.SafeString( + ``, + ); + case "array-string-builder": + objName = value.split("=>")[0].trim(); + outstr = value.split("=>")[1]; + var finalstr = ""; + + objData = extractPropertyByString(character, objName); + + if (!Array.isArray(objData)) { + objData = Object.keys(objData).map((key) => { + return objData[key]; + }); + } + + var regValue = /(?:\*\.|[\w.]+)+/g; + var reg = new RegExp(regValue); + var allmatches = Array.from(outstr.matchAll(reg), (match) => match[0]); + + for (const objSubData of objData) { + for (const m of allmatches) { + if (m === "value") { + finalstr += outstr.replace(m, objSubData); + continue; + } + outstr = outstr.replace(m, extractPropertyByString(objSubData, m)); + } + } + if (finalstr === "") { + finalstr = outstr; + } + finalstr = finalstr.trim(); + finalstr = this.cleanString(finalstr); + return finalstr === value ? "" : finalstr; + case "string": + return value; + default: + return ""; + } } // eslint-disable-next-line no-unused-vars @@ -77,85 +373,130 @@ export class PartySheetForm extends FormApplication { } getData(options) { + // @ts-ignore const hiddenCharacters = game.settings.get("theater-of-the-mind", "hiddenCharacters"); + // @ts-ignore const enableOnlyOnline = game.settings.get("theater-of-the-mind", "enableOnlyOnline"); - let players = this.getPlayerData(); + // @ts-ignore + var customSystems = getCustomSystems(); - if (!enableOnlyOnline) { - players = players.filter((player) => !hiddenCharacters.includes(player.uuid)); - } + const applicableSystems = customSystems.filter((data) => { + // @ts-ignore + return data.system === game.system.id; + }); + let selectedIdx = getSelectedSystem() ? applicableSystems.findIndex((data) => data === getSelectedSystem()) : 0; + // if (applicableSystems.length === 1) { + // selectedIdx = customSystems.findIndex((data) => data === applicableSystems[0]); + // } + + updateSelectedSystem(applicableSystems[selectedIdx]); + var selectedSystem = getSelectedSystem(); + let { name: sysName, author: sysAuthor, players, rowcount } = this.getCustomPlayerData(selectedSystem); + // @ts-ignore return mergeObject(super.getData(options), { hiddenCharacters, enableOnlyOnline, + rowcount, players, + applicableSystems, + selectedName: sysName, + selectedAuthor: sysAuthor, + // @ts-ignore overrides: this.overrides, }); } static get defaultOptions() { + // @ts-ignore return foundry.utils.mergeObject(super.defaultOptions, { id: "totm-party-sheet", classes: ["form"], title: "Party Sheet", + // resizable: true, template: "modules/theater-of-the-mind/templates/party-sheet.hbs", - width: "auto", - height: "auto", + // @ts-ignore + width: "auto", // $(window).width() > 960 ? 960 : $(window).width() - 100, + height: "auto", //$(window).height() > 800 ? 800 : $(window).height() - 100, }); } - // saveHiddenCharacters() { - // const hiddenCharacters = []; - // for (const character of this.characterList) { - // const checkbox = document.getElementById(`hidden-character-${character}`); - // if (checkbox.checked) { - // hiddenCharacters.push(character); - // } - // } - // game.settings.set('theater-of-the-mind', 'hiddenCharacters', hiddenCharacters); - // const closefunc = this.overrides?.onexit; - // if (closefunc) { - // closefunc(); - // } - // super.close(); - // } - - // resetEffects() { - // // this.effects = game.settings.settings.get('monks-little-details.additional-effects').default; - // this.refresh(); - // } - openOptions(event) { event.preventDefault(); const overrides = { onexit: () => { // this.close(); setTimeout(() => { + // @ts-ignore this.render(true); }, 350); }, }; const hcs = new HiddenCharactersSettings(overrides); + // @ts-ignore hcs.render(true); } closeWindow() { + // @ts-ignore this.close(); } openActorSheet(event) { event.preventDefault(); const actorId = event.currentTarget.dataset.actorid; + // @ts-ignore const actor = game.actors.get(actorId.replace("Actor.", "")); actor.sheet.render(true); } + changeSystem(event) { + var selectedSystemName = event.currentTarget.value.split("___")[0]; + var selectedSystemAuthor = event.currentTarget.value.split("___")[1]; + var selectedIndex = + getCustomSystems().findIndex( + (data) => data.name === selectedSystemName && data.author === selectedSystemAuthor, + ) ?? -1; + if (selectedIndex != -1) { + updateSelectedSystem(getCustomSystems()[selectedIndex]); + } + // @ts-ignore + this.render(true); + } + activateListeners(html) { super.activateListeners(html); + // @ts-ignore $('button[name="totm-options"]', html).click(this.openOptions.bind(this)); + // @ts-ignore $('button[name="totm-close"]', html).click(this.closeWindow.bind(this)); + // @ts-ignore $('input[name="totm-actorimage"]', html).click(this.openActorSheet.bind(this)); - // $('button[name="submit"]', html).click(this.saveHiddenCharacters.bind(this)); - // $('button[name="reset"]', html).click(this.resetEffects.bind(this)); + // @ts-ignore + $('select[name="totm-system"]', html).change(this.changeSystem.bind(this)); + // @ts-ignore + $('button[name="feedback"]', html).click(this.onFeedback.bind(this)); + // @ts-ignore + $('button[name="bugreport"]', html).click(this.onBugReport.bind(this)); + // @ts-ignore + $('button[name="discord"]', html).click(this.onDiscord.bind(this)); + } + + async onFeedback(event) { + event.preventDefault(); + const newWindow = window.open(FEEDBACK_URL, "_blank", "noopener,noreferrer"); + if (newWindow) newWindow.opener = undefined; + } + + async onBugReport(event) { + event.preventDefault(); + const newWindow = window.open(BUGREPORT_URL, "_blank", "noopener,noreferrer"); + if (newWindow) newWindow.opener = undefined; + } + + async onDiscord(event) { + event.preventDefault(); + const newWindow = window.open(DISCORD_URL, "_blank", "noopener,noreferrer"); + if (newWindow) newWindow.opener = undefined; } } diff --git a/src/module/app/settings.js b/src/module/app/settings.js index 451fca6..cb09edb 100644 --- a/src/module/app/settings.js +++ b/src/module/app/settings.js @@ -1,6 +1,7 @@ import { HiddenCharactersSettings } from "./hidden-characters-settings"; export const registerSettings = () => { + // @ts-ignore game.settings.register("theater-of-the-mind", "hiddenCharacters", { "scope": "world", "config": false, @@ -8,6 +9,7 @@ export const registerSettings = () => { "type": Array, }); + // @ts-ignore game.settings.register("theater-of-the-mind", "enableOnlyOnline", { "name": "theater-of-the-mind.settings.enable-only-online.name", "hint": "theater-of-the-mind.settings.enable-only-online.hint", @@ -17,6 +19,17 @@ export const registerSettings = () => { "type": Boolean, }); + // @ts-ignore + game.settings.register("theater-of-the-mind", "showDebugInfo", { + "name": "theater-of-the-mind.settings.show-debug-info.name", + "hint": "theater-of-the-mind.settings.show-debug-info.hint", + "scope": "world", + "config": true, + "default": false, + "type": Boolean, + }); + + // @ts-ignore game.settings.registerMenu("theater-of-the-mind", "configureHiddenCharacters", { "name": "", "label": "theater-of-the-mind.hide-sheet.button", @@ -26,18 +39,20 @@ export const registerSettings = () => { "type": HiddenCharactersSettings, }); - game.settings.register("theater-of-the-mind", "enableDarkMode", { - "name": "theater-of-the-mind.settings.enable-dark-mode.name", - "hint": "theater-of-the-mind.settings.enable-dark-mode.hint", - "scope": "world", - "config": true, - "default": false, - "type": Boolean, - "onChange": () => { - // Hooks.call("renderSceneControls"); - }, - }); + // // @ts-ignore + // game.settings.register("theater-of-the-mind", "enableDarkMode", { + // "name": "theater-of-the-mind.settings.enable-dark-mode.name", + // "hint": "theater-of-the-mind.settings.enable-dark-mode.hint", + // "scope": "world", + // "config": true, + // "default": false, + // "type": Boolean, + // "onChange": () => { + // // Hooks.call("renderSceneControls"); + // }, + // }); + // @ts-ignore game.settings.register("theater-of-the-mind", "enableSounds", { "name": "theater-of-the-mind.settings.enable-sounds.name", "hint": "theater-of-the-mind.settings.enable-sounds.hint", diff --git a/src/module/systems/dnd5e.js b/src/module/systems/dnd5e.js new file mode 100644 index 0000000..4605a44 --- /dev/null +++ b/src/module/systems/dnd5e.js @@ -0,0 +1,171 @@ +export /** @type {SystemData} */ +const DND5E = { + "name": "dnd5e", + "system": "dnd5e", + "author": "Built-In", + "offline_excludes": ["npc", "base", "vehicle", "group"], + "rows": [ + [ + { + "name": "Character Sheet", + "type": "charactersheet", + "header": "hide", + "text": "", + }, + { + "name": "Name", + "type": "direct", + "header": "show", + "text": "name {newline} system.details.race", + }, + { + "name": "STR", + "type": "direct", + "header": "show", + "text": "system.abilities.str.value", + }, + { + "name": "DEX", + "type": "direct", + "header": "show", + "text": "system.abilities.dex.value", + }, + { + "name": "CON", + "type": "direct", + "header": "show", + "text": "system.abilities.con.value", + }, + { + "name": "INT", + "type": "direct", + "header": "show", + "text": "system.abilities.int.value", + }, + { + "name": "WIS", + "type": "direct", + "header": "show", + "text": "system.abilities.wis.value", + }, + { + "name": "CHA", + "type": "direct", + "header": "show", + "text": "system.abilities.cha.value", + }, + { + "name": "AC", + "type": "direct", + "header": "show", + "text": "system.attributes.ac.value", + }, + { + "name": "Inv", + "type": "direct", + "header": "show", + "text": "system.skills.inv.passive", + }, + { + "name": "Vision", + "type": "string", + "header": "show", + "text": "", + }, + ], + [ + { + "name": "Spacer1", + "type": "", + "header": "hide", + "text": "", + }, + { + "name": "Classes", + "type": "array-string-builder", + "header": "show", + "text": "classes => name - system.levels", + }, + { + "name": "STR Mod", + "type": "direct", + "header": "hide", + "text": "system.abilities.str.mod", + }, + { + "name": "DEX Mod", + "type": "direct", + "header": "hide", + "text": "system.abilities.dex.mod", + }, + { + "name": "CON Mod", + "type": "direct", + "header": "hide", + "text": "system.abilities.con.mod", + }, + { + "name": "INT Mod", + "type": "direct", + "header": "hide", + "text": "system.abilities.int.mod", + }, + { + "name": "WIS Mod", + "type": "direct", + "header": "hide", + "text": "system.abilities.wis.mod", + }, + { + "name": "CHA Mod", + "type": "direct", + "header": "hide", + "text": "system.abilities.cha.mod", + }, + { + "name": "Per", + "type": "direct", + "header": "show", + "text": "system.skills.prc.passive", + }, + { + "name": "Ins", + "type": "direct", + "header": "show", + "text": "system.skills.ins.passive", + }, + { + "name": "Senses", + "type": "direct-complex", + "header": "hide", + "text": [ + { + "type": "exists", + "value": "system.attributes.senses.darkvision", + "text": "Darkvision: system.attributes.senses.darkvision", + }, + { + "type": "exists", + "value": "system.attributes.senses.blindsight", + "text": "Blindsight: system.attributes.senses.blindsight", + }, + { + "type": "exists", + "value": "system.attributes.senses.tremorsense", + "text": "Tremorsense: system.attributes.senses.tremorsense", + }, + { + "type": "exists", + "value": "system.attributes.senses.truesight", + "text": "Truesight: system.attributes.senses.truesight", + }, + { + "type": "exists", + "value": "system.attributes.senses.special", + "text": "Special: system.attributes.senses.special", + }, + ], + }, + ], + ], +}; diff --git a/src/module/theater-of-the-mind.js b/src/module/theater-of-the-mind.js index 6ab0056..c8f26d1 100644 --- a/src/module/theater-of-the-mind.js +++ b/src/module/theater-of-the-mind.js @@ -2,20 +2,43 @@ import { THEATER_SOUNDS } from "./sounds.js"; import { registerSettings } from "./app/settings.js"; import { PartySheetForm } from "./app/party-sheet.js"; +import { addCustomSystem, toProperCase } from "./utils.js"; let isSyrinscapeInstalled = false; let isMidiQoLInstalled = false; +let currentPartySheet = null; -function log(...message) { +/** + * + * @param {any} message The message to send to console.log + */ +function log(message) { console.log("Theater of the Mind | ", message); } +/** + * Checks if the current environment is ForgeVTT + * @returns {boolean} True if the current environment is ForgeVTT + */ +function isForgeVTT() { + // @ts-ignore + if (!(typeof ForgeVTT !== "undefined")) { + return false; + } + // @ts-ignore + return ForgeVTT.usingTheForge; +} + +// @ts-ignore Handlebars.registerHelper("hccontains", function (needle, haystack, options) { + // @ts-ignore needle = Handlebars.escapeExpression(needle); + // @ts-ignore haystack = game.settings.get("theater-of-the-mind", "hiddenCharacters") ?? []; return haystack.indexOf(needle) > -1 ? options.fn(this) : options.inverse(this); }); +// @ts-ignore Handlebars.registerHelper("hcifgte", function (v1, v2, options) { if (v1 >= v2) { return options.fn(this); @@ -23,6 +46,69 @@ Handlebars.registerHelper("hcifgte", function (v1, v2, options) { return options.inverse(this); }); +// @ts-ignore +Handlebars.registerHelper("hciflte", function (v1, v2, options) { + if (v1 <= v2) { + return options.fn(this); + } + return options.inverse(this); +}); + +// @ts-ignore +Handlebars.registerHelper("checkIndex", function (index, options) { + if (index % 2 == 0) { + return options.fn(this); + } + return options.inverse(this); +}); + +// @ts-ignore +Handlebars.registerHelper("hcifhidden", function (row, options) { + var key = options.hash["key"]; + var myoptions = row[key]?.options ?? {}; + + if (myoptions?.header === "show") { + return options.inverse(this); + } else { + return options.fn(this); + } +}); + +// @ts-ignore +Handlebars.registerHelper("getAlignment", function (row, key) { + var myoptions = row[key]?.options ?? {}; + return myoptions.align ?? "center"; +}); + +// @ts-ignore +Handlebars.registerHelper("getVAlignment", function (row, key) { + var myoptions = row[key]?.options ?? {}; + if (myoptions.valign === "top" || myoptions.valign === "bottom") { + return myoptions.valign; + } else { + return "inherit"; + } +}); + +// @ts-ignore +Handlebars.registerHelper("getColSpan", function (row, key) { + var myoptions = row[key]?.options ?? {}; + return myoptions?.colspan ?? 1; +}); + +// @ts-ignore +Handlebars.registerHelper("getMaxWidth", function (row, key) { + var myoptions = row[key]?.options ?? {}; + return myoptions?.maxwidth ? `${myoptions?.maxwidth}px` : "none"; +}); + +// @ts-ignore +Handlebars.registerHelper("getMinWidth", function (row, key) { + var myoptions = row[key]?.options ?? {}; + return myoptions?.minwidth ? `${myoptions?.minwidth}px` : "auto"; +}); + +// @ts-ignore Handlebars.registerHelper("eachInMap", function (map, block) { var out = ""; Object.keys(map).map(function (prop) { @@ -31,21 +117,149 @@ Handlebars.registerHelper("eachInMap", function (map, block) { return out; }); +// @ts-ignore +Handlebars.registerHelper("debug", function (data) { + console.log(data); + return ""; +}); + +// @ts-ignore +Handlebars.registerHelper("getKeys", function (obj, options) { + const keys = Object.keys(obj); + let result = ""; + for (let i = 0; i < keys.length; i++) { + result += options.fn(keys[i]); + } + return result; +}); + +// @ts-ignore +Handlebars.registerHelper("getData", function (obj, key) { + return obj[key].text; +}); + +// @ts-ignore Handlebars.registerHelper("toUpperCase", function (str) { return str.toUpperCase(); }); -let currentPartySheet = null; +// @ts-ignore +Handlebars.registerHelper("toProperCase", function (str) { + return toProperCase(str); +}); +// @ts-ignore +Handlebars.registerHelper("ifCond", function (v1, operator, v2, options) { + switch (operator) { + case "==": + return v1 == v2 ? options.fn(this) : options.inverse(this); + case "===": + return v1 === v2 ? options.fn(this) : options.inverse(this); + case "!=": + return v1 != v2 ? options.fn(this) : options.inverse(this); + case "!==": + return v1 !== v2 ? options.fn(this) : options.inverse(this); + case "<": + return v1 < v2 ? options.fn(this) : options.inverse(this); + case "<=": + return v1 <= v2 ? options.fn(this) : options.inverse(this); + case ">": + return v1 > v2 ? options.fn(this) : options.inverse(this); + case ">=": + return v1 >= v2 ? options.fn(this) : options.inverse(this); + case "&&": + return v1 && v2 ? options.fn(this) : options.inverse(this); + case "||": + return v1 || v2 ? options.fn(this) : options.inverse(this); + default: + return options.inverse(this); + } +}); + +/** + * + */ function togglePartySheet() { if (currentPartySheet?.rendered) { currentPartySheet.close(); } else { currentPartySheet = new PartySheetForm(); + // @ts-ignore currentPartySheet.render(true); } } +/** + * Load all the user-provided templates for systems + * @param {string} path The path to the template + * @returns {Promise} A promise that resolves when the template is loaded + */ +async function loadSystemTemplate(path) { + try { + const templateName = path.split("/").pop().split(".")[0]; + log(`Loading template: ${templateName}`); + const template = JSON.parse(await fetch(path).then((r) => r.text())); + if (template.name && template.author && template.system && template.rows) { + console.log(`${path} - Good Template`); + addCustomSystem(template); + } else { + console.log(`${path} - Bad Template`); + } + } catch (e) { + console.log(`${path} - Failed to Load. See error below.`); + console.error(e); + } +} + +/** + * Load all the user-provided templates for systems + */ +async function loadSystemTemplates() { + // Look inside the "totm" folder. Any JSON file inside should be loaded + const templatePaths = []; + // @ts-ignore + + var assetPrefix = "data"; + + if (isForgeVTT()) { + console.log("Detected ForgeVTT"); + // @ts-ignore + assetPrefix = ForgeVTT.ASSETS_LIBRARY_URL_PREFIX + (await ForgeAPI.getUserId()) + "/"; + } + + try { + // @ts-ignore + await FilePicker.createDirectory(assetPrefix, "totm"); //, { bucket: "public" } + } catch (e) { + console.log("Failed creating TOTM directory. It probably already exists."); + } + + // @ts-ignore + var templateFiles = await FilePicker.browse(assetPrefix, "totm"); // `modules/${MODULE_NAME}/templates`); + + templateFiles.files.forEach((file) => { + if (file.endsWith(".json")) { + templatePaths.push(file); + } + }); + + templatePaths.forEach(async (path) => { + await loadSystemTemplate(path); + }); + // for (const file of templateFiles.files) { + // if (file.endsWith(".html")) { + // templatePaths.push(file); + // } + // } +} + +/** + * + * @param {string} weapon The weapon type + * @param {boolean} crit If the hit was a crit + * @param {boolean} hitmiss If the action was a hit or miss + * @param {object} override Setting overrides + */ async function playSound(weapon, crit, hitmiss, override = null) { if (!isSyrinscapeInstalled || !isMidiQoLInstalled) { return; @@ -53,6 +267,7 @@ async function playSound(weapon, crit, hitmiss, override = null) { const hitmisscrit = override ? "any" : crit ? "critical" : hitmiss ? "hit" : "miss"; + // @ts-ignore if (!game.settings.get("theater-of-the-mind", "enableSounds")) { return; } @@ -71,11 +286,13 @@ async function playSound(weapon, crit, hitmiss, override = null) { if (!soundid) { log(`Key found: [${weapon.toLowerCase()}], No sound sub-type found [${subsound}].`); } else { + // @ts-ignore game.syrinscape.playElement(soundid); } } /* Hooks */ +// @ts-ignore Hooks.on("init", () => { log("Initializing"); @@ -83,6 +300,7 @@ Hooks.on("init", () => { }); // +// @ts-ignore Hooks.on("midi-qol.AttackRollComplete", async (roll) => { const weapon = roll.item.name; const roll_results = roll.attackTotal; @@ -95,6 +313,7 @@ Hooks.on("midi-qol.AttackRollComplete", async (roll) => { } }); +// @ts-ignore Hooks.on("midi-qol.preambleComplete", async (roll) => { if (roll?.item?.type != "spell") { return; @@ -102,34 +321,46 @@ Hooks.on("midi-qol.preambleComplete", async (roll) => { playSound(roll.item.name, false, false, "any"); }); +// @ts-ignore Hooks.on("ready", async () => { log("Ready"); + // @ts-ignore isSyrinscapeInstalled = game.modules.get("fvtt-syrin-control")?.active || false; log(`Syrinscape is installed: ${isSyrinscapeInstalled}`); + // @ts-ignore isMidiQoLInstalled = game.modules.get("midi-qol")?.active || false; log(`Midi-QoL is installed: ${isMidiQoLInstalled}`); const soundsReady = isSyrinscapeInstalled && isMidiQoLInstalled; log(`Sounds enabled: ${soundsReady}`); + + log("Loading templates"); + await loadSystemTemplates(); }); +// @ts-ignore Hooks.on("renderPlayerList", () => { + // @ts-ignore const showOnlyOnlineUsers = game.settings.get("theater-of-the-mind", "enableOnlyOnline"); + // @ts-ignore if (!game.user.isGM || !showOnlyOnlineUsers) { return; } - if (currentPartySheet.rendered) { + if (currentPartySheet?.rendered) { // PartySheetDialog.data.content = convertPlayerDataToTable(); currentPartySheet.render(true); } }); +// @ts-ignore Hooks.on("renderSceneControls", () => { + // @ts-ignore const showButton = game.user.isGM; + // @ts-ignore const button = $(` { `); button.click(() => togglePartySheet()); + // @ts-ignore const controls = $("#tools-panel-token"); if (showButton && controls.find(".control-tool[data-tool='PartySheet']")) { diff --git a/src/module/utils.js b/src/module/utils.js index 1342e48..6fa56ad 100644 --- a/src/module/utils.js +++ b/src/module/utils.js @@ -1,3 +1,13 @@ +import { DND5E } from "./systems/dnd5e"; + +var customSystems = [DND5E]; +export var selectedSystem = null; + +/** + * Converts a string to proper case. + * @param {string} inputString - The input string to convert. + * @returns {string} - The converted string in proper case. + */ export function toProperCase(inputString) { return inputString .toLowerCase() @@ -5,3 +15,108 @@ export function toProperCase(inputString) { .map((word) => word.charAt(0).toUpperCase() + word.slice(1)) .join(" "); } + +/** + * Updates the selected system. + * @param {*} system - The system to select. + */ +export function updateSelectedSystem(system) { + selectedSystem = system; +} + +/** + * Retrieves the selected system. + * @returns {*} - The selected system. + */ +export function getSelectedSystem() { + return selectedSystem; +} + +/** + * Adds a custom system to the list of systems. + * @param {*} system - The custom system to add. + */ +export function addCustomSystem(system) { + customSystems.push(system); +} + +/** + * Retrieves the list of custom systems. + * @returns {*} - The list of custom systems. + */ +export function getCustomSystems() { + return customSystems; +} + +/** + * Retrieves a nested property from an object using a string path. + * @param {object} obj - The object from which to retrieve the property. + * @param {string | boolean} path - A string path to the property, with each nested property separated by a dot. + * @returns {*} - The value of the property at the end of the path, or `undefined` if any part of the path is undefined. + * @example + * // returns 2 + * extractPropertyByString({a: {b: 2}}, "a.b"); + */ +export function extractPropertyByString(obj, path) { + if (typeof path === "boolean" || typeof path === "number") { + return path; + } + + const keys = path.split("."); + + let currentObject = obj; + + for (let key of keys) { + currentObject = currentObject[key]; + + // If the property is not found, return undefined + if (currentObject === undefined) { + return undefined; + } + } + + if (currentObject && Object.prototype.hasOwnProperty.call(currentObject, "value")) { + return currentObject.value; + } + + return currentObject; +} + +/** + * Takes a JSON object and trims the strings for value, else, and match. + * @param {*} item - The item to trim. + * @returns {*} - The item with trimmed strings. + */ +export function trimIfString(item) { + if (item.text && typeof item.text === "string") { + item.text = item.text.trim(); + } + if (item.else && typeof item.else === "string") { + item.else = item.else.trim(); + } + if (item.matches && typeof item.matches === "string") { + item.matches = item.matches.trim(); + } + + return item; +} + +/** + * Parses out plus sumbols and adds values together. + * @param {*} value - The value to parse. + * @returns {*} - The value with the pluses parsed out. + */ +export function parsePluses(value) { + // Match patterns with optional spaces around {+} + let match = value.match(/(\d+)\s*\{\+\}\s*(\d+)|\d+\{\+\}\d+/); + if (!match) { + return value; + } + do { + const numbers = match[0].trim().split("{+}").map(Number); + const result = numbers[0] + numbers[1]; + value = value.replace(match[0], result.toString()); + } while ((match = value.match(/(\d+)\s*\{\+\}\s*(\d+)|\d+\{\+\}\d+/))); + + return value; +} diff --git a/src/styles/theater-of-the-mind.scss b/src/styles/theater-of-the-mind.scss index bf44438..5c4b586 100644 --- a/src/styles/theater-of-the-mind.scss +++ b/src/styles/theater-of-the-mind.scss @@ -1,11 +1,21 @@ -#totm-dialog-darkmode { - background:none; - background-color:transparent; - color:white; +#totm-system-select { + display: flex; + margin-top: 0.25rem; + width: 100%; +} - .dialog-button { - color:white; - } +.totm-toprow { + display:flex; + flex-direction:row; + flex-wrap:nowrap; +} + +.totm-options { + max-width: 400px; +} + +.totm-ps-no-systems { + padding: 1rem; } .totm-hc-form { @@ -37,6 +47,27 @@ #totm-ps-table { text-align:center; + th { + padding: 0.3em; + word-break: break-word; + } + + tr { + background-color: none; + } + + tr.dark { + background-color: rgba(0,0,0,0.25); + } + + tr.light { + background-color: rgba(0,0,0,0.1); + } + + .flex-tc { + display: inline-flex; + } + .namerace { padding-left:10px; display:flex; @@ -46,7 +77,13 @@ } td { - border: 1px solid darkgray; + border: 1px solid darkgray; + } + + tbody { + td { + padding: .25em; + } } .totm-senses { @@ -58,6 +95,11 @@ padding-right:5px; } + .totm-dc { + overflow-wrap: break-word; + word-break: normal; + } + .totm-ps-name-bar { width:100%; display:flex; diff --git a/src/templates/party-sheet.hbs b/src/templates/party-sheet.hbs index 86c9914..e079991 100644 --- a/src/templates/party-sheet.hbs +++ b/src/templates/party-sheet.hbs @@ -1,64 +1,75 @@ - {{#unless enableOnlyOnline}} - {{localize "theater-of-the-mind.hide-sheet.button" }} - {{/unless}} - - {{#if players}} - - - {{ localize "theater-of-the-mind.party-sheet.name" }}{{ localize "theater-of-the-mind.party-sheet.race"}} - {{#each players.1.stats}} - {{toUpperCase @key}} - {{/each}} - AC - Inv - {{localize "theater-of-the-mind.party-sheet.senses"}} - - - - {{localize "theater-of-the-mind.party-sheet.classes"}} - {{#each players.1.stats}} - + + {{#unless enableOnlyOnline}} + {{localize "theater-of-the-mind.hide-sheet.button" }} + {{/unless}} + + + + + + + + + + + + {{#if applicableSystems.length}} + + {{#each applicableSystems as |system|}} + {{system.name}} - {{system.author}} {{/each}} - Per - Ins - - - - {{#each players as |player|}} - - - - {{{player.img}}} - - {{player.name}} - {{player.race}} - {{player.classNames}} - - - - {{#each player.stats as |stat|}} - {{stat.value}} - {{/each}} - {{player.ac}} - {{player.passives.inv}} - {{player.senses}} - - - {{#each player.stats as |stat|}} - {{#hcifgte stat.mod 0}} - +{{stat.mod}} + + {{#if players}} + + + {{#with players.[0] as |player_data|}} + {{#each player_data as |row|}} + + {{#getKeys row}} + {{#hcifhidden row key=this}} + + {{else}} + {{this}} + {{/hcifhidden}} + {{/getKeys}} + + {{/each}} + {{/with}} + + {{#each players as |player_data|}} + {{#each player_data as |player_row|}} + {{stat.mod}} - {{/hcifgte}} + class="light" + {{/checkIndex}} + > + {{#getKeys player_row}} + + {{getData player_row this}} + + {{/getKeys}} + {{/each}} - {{player.passives.prc}} - {{player.passives.ins}} - - {{/each}} - + {{/each}} + + + + {{else}} + {{ localize "theater-of-the-mind.party-sheet.no-players" }} + {{/if}} + {{else}} - {{ localize "theater-of-the-mind.party-sheet.no-players" }} + {{ localize "theater-of-the-mind.party-sheet.no-systems" }} {{/if}} + Close diff --git a/test/example.test.js b/test/example.test.js index fc23fc4..eb4f251 100644 --- a/test/example.test.js +++ b/test/example.test.js @@ -2,8 +2,8 @@ // // SPDX-License-Identifier: MIT -describe('An example test', () => { - it('will always succeed', () => { +describe("An example test", () => { + it("will always succeed", () => { expect(true).toBeTruthy(); }); }); diff --git a/test/utils.test.js b/test/utils.test.js new file mode 100644 index 0000000..1649535 --- /dev/null +++ b/test/utils.test.js @@ -0,0 +1,36 @@ +import { parsePluses } from "../src/module/utils"; +// @ts-ignore +describe("Utils testing", () => { + // @ts-ignore + describe("Plus parsing", () => { + it("will parse a simple request", () => { + // @ts-ignore + expect(parsePluses("1 {+} 2")).toEqual("3"); + }); + + it("will parse a simple request with a space", () => { + // @ts-ignore + expect(parsePluses("1 {+} 2")).toEqual("3"); + }); + + it("will parse a complex request", () => { + // @ts-ignore + expect(parsePluses("1 {+} 2 {+} 3")).toEqual("6"); + }); + + it("will fail a complex request", () => { + // @ts-ignore + expect(parsePluses("1 {+} 2 {+} 3 {+}")).toEqual("6 {+}"); + }); + + it("will fail a complex request again", () => { + // @ts-ignore + expect(parsePluses("1 {+} 2 {+} 3 {+} text")).toEqual("6 {+} text"); + }); + + it("will parse a complex request again", () => { + // @ts-ignore + expect(parsePluses("1 {+} 2 {+} 3 {+} 10")).toEqual("16"); + }); + }); +});