First off, thank you for your interest in contributing to foundry-vtt-types — we need all the help we can get!
The following is a set of guidelines for contributing to foundry-vtt-types. These are mostly guidelines, not rules. Use your best judgment, and feel free to propose changes to this document in a pull request.
- Documentation: README.md, Wiki
- Issue tracker: Issues
- Project boards
- Communication: League Discord (ask for the TypeScript related channels if you're not already in them)
This section guides you through submitting a bug report for foundry-vtt-types. Following these guidelines helps maintainers and the community understand your report and reproduce the behavior.
- Make sure you are using the latest version of foundry-vtt-types for the corresponding Foundry VTT Version.
- Check if the problem has already been reported in our issue tracker.
Bugs are tracked in our issue tracker. When creating a bug report, please provide the following information by using the template.
- Provide the exact version of Foundry VTT and foundry-vtt-types that exhibits the problem.
- Provide minimal steps to reproduce the behavior.
- Describe the problem in a clear and concise way. This includes the actual behavior.
- Describe the expected behavior.
- Optionally, add any additional context if it makes sense.
You can also suggest ideas for the project beyond plain Foundry VTT types. The guidelines are similar to those for bug reporting. The most important one being: Use the template to give all the relevant information about your request.
If you are unsure where to start, you can look through issues tagged with help wanted. These are issues that we would like to have help with.
We also recommend taking a look at the corresponding project board to make sure that nobody is working on your issue yet. Additionally, please let us know if you start working on a specific issue (by writing a comment in that issue) so that we can avoid doing duplicate work.
We use a very simple branching model. Development for the current Foundry VTT version happens on the main
branch.
Additionally, we have branches for older supported Foundry VTT versions. They are named according to the Foundry VTT
version to which they belong (e.g. foundry-0.8.x
). All changes for the type definitions for a given Foundry VTT
version need to be made through Pull Requests towards the corresponding branch.
When creating a pull request, please provide the following information:
- What issue does this pull request correspond to (if any)?
- What does this pull request implement?
- What changes are made in this pull request?
We use prettier to automatically format the code and have ESlint check for the correct formatting. This even runs automatically as a pre-commit hook, so usually you don't have to care for much here. However, there is one additional style guideline that prettier doesn't enforce for us:
In TSDoc comments, always make sure to align the -
for all @param
s.
In very rare occasions, it is acceptable to disable prettier for a specific part of the code to improve the formatting manually, e.g. for deeply nested conditional types, which are simply unreadable if we let prettier format them. See Prettier – Ignoring Code to find out how to do this.
- Try to match the source code Foundry VTT as closely as possible in your type definitions. In particular, the order of declarations should be exactly the same. This allows for easy side by side viewing of the original source code and the type definitions, making the life of code reviewers much easier :)
- Try not to pollute the global namespace with custom types that are not declared by Foundry VTT itself (typedefs from
Foundry VTT should be declared). Instead, use a namespace named like the related class and put your custom type in
there. Alternatively, if you don't want the type to be easily accessible at all, make your declaration file a module
(e.g. by adding an empty export), declare the things should be visible globally in a
declare global {}
block and simply put the things that should not be visible globally outside that block. - The file structure follows the structure of Foundry VTT but additionally, every class has its own file and the files are structured by class hierarchy. Declarations for code that is not a class should be structured in a sensible way, but there are no clear guidelines.
- Generic utility types not defined in Foundry VTT belong in
src/types/utils.d.ts
. - Utility types that are specific to Foundry VTT belong in
src/types/helperTypes.d.ts
. - Augments for libraries bundled with Foundry VTT belong in their corresponding file in
src/types/augments
. - Write tests where applicable. Not everything needs to be tested, these are just type definitions after all. But in particular for complicated type definitions it makes a lot of sense to add tests.
If the type of the options is different from that of the parent class, provide a new Options
interface
in the
namespace
of the class you are adding types for. It makes sense to add the default values in that type via
@defaultValue
TSDoc. Use this interface as return type for getDefaultOptions
.
If the type does not differ, just use the Options
interface from the parent class.
In both cases, provide the default value for getDefaultOptions
in TSDoc.
Example:
declare class ActorSheet<Options extends ActorSheet.Options = ActorSheet.Options> extends DocumentSheet<
Options,
Actor.ConfiguredInstance
> {
/**
* @defaultValue
* ```typescript
* foundry.utils.mergeObject(super.defaultOptions, {
* height: 720,
* width: 800,
* template: "templates/sheets/actor-sheet.html",
* closeOnSubmit: false,
* submitOnClose: true,
* submitOnChange: true,
* resizable: true,
* baseApplication: "ActorSheet",
* dragDrop: [{ dragSelector: ".item-list .item", dropSelector: null }],
* token: null,
* });
* ```
*/
static get defaultOptions(): ActorSheet.Options;
/* ... */
}
If the type is not configurable by the user, it should most likely be NameOfTheClass.AnyConstructor
. This will also
allow deriving classes to be used as value. In rare occasions (i.e. when really only instances of this specific class
may be assigned, no deriving classes), typeof NameOfTheClass
can be used.
Example (documentClass
is configurable, collection
is not):
/**
* Configuration for the Actor document
*/
Actor: {
/**
* @defaultValue `Actor`
*/
documentClass: ConfiguredDocumentClassOrDefault<typeof Actor>;
/**
* @defaultValue `Actors`
*/
collection: Actors.AnyConstructor;
}
This is just a static property of the class. Add it to the class at the very bottom.
Example:
In Foundry VTT
class AVSettings {
/* ... */
}
AVSettings.AV_MODES = {
DISABLED: 0,
AUDIO: 1,
VIDEO: 2,
AUDIO_VIDEO: 3,
};
Type definition
declare class AVSettings {
/* ... */
static AV_MODES: {
DISABLED: 0;
AUDIO: 1;
VIDEO: 2;
AUDIO_VIDEO: 3;
};
}
There are some comments we use to mark places in the code, where we should have a look later on. For things that could be extended or improved later, but are not needed for the proper functioning of the types, TODO comments can be used.
// TODO: Some description to explain what should be done
When updating types, especially between major Foundry versions, it happens that types are referenced in one class, that are not defined or updated yet. In those cases FIXME comments should be used. Ideally those should also have the final type code in their description. In general it is favorable to have these places just commented instead of the types not compiling.
// FIXME: SomeNotYetExistingType // This will be added in PR #...
If you've made it this far: Thanks for reading and for trying to contribute. It is much appreciated. We're hoping to see you soon on the League Discord!