diff --git a/.github/homebrew-schema.json b/.github/homebrew-schema.json new file mode 100644 index 0000000..09a778b --- /dev/null +++ b/.github/homebrew-schema.json @@ -0,0 +1,724 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "version": "1.10.22", + "type": "object", + "description": "Homebrew for 5etools. Should include arrays titled similarly to the main site data, e.g. `spell` or `class`", + "$defs": { + "wrappedAdventureBookDataArray": { + "type": "array", + "items": { + "type": "object", + "properties": { + "id": { + "type": "string" + }, + "source": { + "$ref": "util.json#/$defs/source" + }, + "data": {} + }, + "required": [ + "id", + "source", + "data" + ], + "additionalProperties": false + }, + "minItems": 1, + "uniqueItems": true + }, + "_meta": { + "description": "Metadata for the included data arrays", + "type": "object", + "properties": { + "sources": { + "type": "array", + "items": { + "type": "object", + "description": "A set of properties describing a \"source.\" A source could be, for example, a homebrew PDF, book, or blog post.", + "properties": { + "json": { + "$ref": "util.json#/$defs/sourceJson" + }, + "abbreviation": { + "type": "string", + "description": "Abbreviated form of the source, to display on the site." + }, + "color": { + "type": "string", + "description": "HTML hex color code this source should use when displayed in lists, e.g. 'ff00ff'", + "pattern": "^([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$" + }, + "full": { + "type": "string", + "description": "Full title of the source, to display on the site." + }, + "authors": { + "type": "array", + "description": "A list of authors who created the homebrew source.", + "items": { + "type": "string", + "description": "Author name." + } + }, + "convertedBy": { + "type": "array", + "description": "An optional list of people who contributed to converting the source to 5etools format.", + "items": { + "type": "string", + "description": "Contributor name." + } + }, + "dateReleased": { + "type": "string", + "format": "date", + "description": "The date of release of the source, in the format YYYY-MM-DD (RFC3339)." + }, + "version": { + "type": "string", + "description": "The source version, e.g. \"1.2.3\"." + }, + "url": { + "type": "string", + "description": "A direct link to the source, if available in web form or on a store.", + "minLength": 3 + }, + "partnered": { + "description": "If this is a \"partnered\" source; usually one which is available and similarly marked on D&D Beyond.", + "type": "boolean" + }, + "targetSchema": { + "deprecated": true, + "type": "string", + "description": "The target schema version in 5etools, e.g. \"1.2.3\"." + } + }, + "required": [ + "json", + "abbreviation", + "full", + "version" + ], + "additionalProperties": false + }, + "minItems": 1, + "uniqueItems": true + }, + "spellSchools": { + "type": "object", + "description": "Object names are spell school abbreviations (e.g. `\"X\"`); values should be objects with `\"full\"`` (used in the main entry, e.g. \"Evocation\") and `\"short\"` (used in the list view, e.g. `\"Evoc.\"`) key/values.", + "patternProperties": { + ".*": { + "type": "object", + "properties": { + "full": { + "type": "string" + }, + "short": { + "type": "string" + }, + "color": { + "type": "string", + "description": "HTML hex color code this source should use when displayed in lists, e.g. 'ff00ff'", + "pattern": "^([a-fA-F0-9]{6}|[a-fA-F0-9]{3})$" + } + }, + "required": [ + "full", + "short" + ] + } + } + }, + "spellDistanceUnits": { + "type": "object", + "description": "Object names are spell distance units (e.g. `\"hectares\"`); values should be objects with optional `\"singular\"`` (singular form of the unit, e.g. \"foot\" for the singular of \"feet\"--if unspecified, a trailing \"s\" is removed from the plural version, if it exists, and the result is used as the singular form) and `\"feetPerUnit\"` (e.g. for a \"yards\" custom unit, this would be `3`, as there are three feet in a yard) key/values.", + "patternProperties": { + ".*": { + "type": "object", + "properties": { + "feetPerUnit": { + "type": "number" + }, + "singular": { + "type": "string" + } + }, + "required": [ + "feetPerUnit" + ] + } + } + }, + "optionalFeatureTypes": { + "type": "object", + "description": "Object names are optional feature \"type\" shorthands (e.g. \"EI\" for \"Eldritch Invocation\" which will be displayed in the list view as a sortable column", + "patternProperties": { + ".*": { + "type": "string" + } + } + }, + "psionicTypes": { + "type": "object", + "description": "Object names are psionic type abbreviations (e.g. `\"X\"`); values should be objects with `\"full\"`` (used in the main entry, e.g. \"Greater Discipline\") and `\"short\"` (used in the list view, e.g. `\"G. Discipline\"`) key/values.", + "patternProperties": { + ".*": { + "type": "object", + "properties": { + "full": { + "type": "string" + }, + "short": { + "type": "string" + }, + "hasOrder": { + "description": "If this type has a psionic order.", + "type": "boolean" + }, + "isAltDisplay": { + "description": "If this type should display its psionic type/order with the format \"Greater Discipline (Awakened)\" instead of the standard \"Awakened Greater Discipline\"", + "type": "boolean" + } + }, + "required": [ + "full", + "short" + ] + } + } + }, + "currencyConversions": { + "type": "object", + "description": "Keys should be uniquely-named value conversion objects, and can be referenced from item entities as \"currencyConversion\": \"\". The currency conversion info will then be used when rendering the value of the item.", + "patternProperties": { + ".*": { + "type": "array", + "items": { + "type": "object", + "properties": { + "coin": { + "type": "string", + "description": "Coin abbreviation, e.g. \"gp\"" + }, + "mult": { + "type": "number", + "description": "A multiplier for converting copper to this currency, e.g. \"0.01\" for standard gold pieces" + }, + "isFallback": { + "type": "boolean", + "description": "If true, this currency will be used as a fallback when the copper value of the item is a fractional value (e.g. a single ball bearing is worth 0.1 cp; marking gold as the fallback currency would have this be converted to gold)." + } + }, + "required": [ + "coin", + "mult" + ] + }, + "minItems": 1, + "uniqueItems": true + } + } + }, + "dateAdded": { + "type": "integer", + "description": "The epoch timestamp (in seconds) when the homebrew was added to the repository. Not guaranteed to be anywhere near accurate." + }, + "dateLastModified": { + "type": "integer", + "description": "The epoch timestamp (in seconds) when the homebrew was last modified. Not guaranteed to be anywhere near accurate." + }, + "_dateLastModifiedHash": { + "type": "string", + "description": "A file hash used to automatically update the value of \"dateLastModified\". Should not be manually created/edited.", + "minLength": 10, + "maxLength": 10 + }, + "dependencies": { + "description": "A map of `\"\": [\"\", ..., \"\"]`. Entities from these sources can then be extended/referenced in this file.\nNote: when copying classes/subclasses/class features/subclass features, the array should consist of \"\", ..., \"\" items, where \"classIdentifierN\" matches the keys in \"5etools/data/class/index.json\" (when copying class/etc. homebrew, normal \"source\"-based linking applies).", + "type": "object", + "patternProperties": { + "^[a-zA-Z]+$": { + "type": "array", + "items": { + "type": "string" + }, + "minItems": 1, + "uniqueItems": true + } + } + }, + "includes": { + "description": "Structure as per \"dependencies\". Additional sources to be included when loading the file.", + "type": "object", + "patternProperties": { + "^[a-zA-Z]+$": { + "type": "array", + "items": { + "type": "string" + }, + "minItems": 1, + "uniqueItems": true + } + } + }, + "internalCopies": { + "description": "An array of keys that are copied from within the current document. e.g. \"item\", \"monsterFluff\", \"background\" etc.", + "type": "array", + "items": { + "type": "string" + }, + "minItems": 1, + "uniqueItems": true + }, + "fonts": { + "description": "A map of \"font family\" to font URL.", + "type": "object", + "patternProperties": { + "^[a-zA-Z0-9]+$": { + "type": "string", + "minLength": 3 + } + } + }, + "unlisted": { + "description": "If this homebrew file should be ignored/hidden by any indexer.", + "type": "boolean" + }, + "status": { + "description": "An overall status for the homebrew.\n\"ready\" indicates that this brew is ready for use, and is in an internally consistent state.\n\"wip\" indicates that this brew is e.g. incomplete, or partially migrated between versions of the source document(s).\n\"invalid\" indicates that using this brew is inadvisable, because while it is schema-passing, it breaks clients which attempt to use it.\n\"deprecated\" indicates this brew is ready for use, but that using it is inadvisable, because e.g. it has been superseded by another brew.", + "type": "string", + "enum": [ + "ready", + "wip", + "invalid", + "deprecated" + ] + } + }, + "required": [ + "sources", + "dateAdded", + "dateLastModified" + ], + "additionalProperties": false + }, + "spellList": { + "type": "array", + "items": { + "$ref": "#/$defs/_spellListItem" + }, + "minItems": 1, + "uniqueItems": true + }, + "_spellListItem": { + "oneOf": [ + { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "source": { + "$ref": "util.json#/$defs/source" + }, + "spellListType": { + "type": "string", + "enum": [ + "groups" + ] + }, + "spells": { + "type": "array", + "items": { + "$ref": "util.json#/$defs/spellListSpellRef" + }, + "minItems": 1, + "uniqueItems": true + } + }, + "required": [ + "name", + "source", + "spellListType", + "spells" + ], + "additionalProperties": false + }, + { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "source": { + "$ref": "util.json#/$defs/source" + }, + "spellListType": { + "type": "string", + "const": "variantClass" + }, + "className": { + "type": "string" + }, + "classSource": { + "$ref": "util.json#/$defs/source" + }, + "spells": { + "type": "array", + "items": { + "$ref": "util.json#/$defs/spellListSpellRef" + }, + "minItems": 1, + "uniqueItems": true + } + }, + "required": [ + "name", + "source", + "spellListType", + "className", + "classSource", + "spells" + ], + "additionalProperties": false + } + ] + } + }, + "properties": { + "_meta": { + "$ref": "#/$defs/_meta" + }, + "$schema": { + "description": "An optional key that allows you specify the schema you want to verify against in compatible IDEs.\nIt is advised that you leave this key out when submitting to the repo.", + "type": "string", + "examples": [ + "../_schema-fast/homebrew.json", + "../_schema/homebrew.json", + "https://raw.githubusercontent.com/TheGiddyLimit/5etools-utils/master/schema/brew-fast/homebrew.json", + "https://raw.githubusercontent.com/TheGiddyLimit/5etools-utils/master/schema/brew/homebrew.json" + ] + }, + "blocklist": { + "description": "An array of objects to blocklist from display on the site.\nUse of this in public brew files is strongly discouraged.", + "type": "array", + "items": { + "type": "object", + "properties": { + "displayName": { + "type": "string" + }, + "hash": { + "type": "string", + "description": "A unique reference for the removed item. Use the blocklist tool on the site to generate this." + }, + "category": { + "type": "string" + }, + "source": { + "anyOf": [ + { + "$ref": "util.json#/$defs/source" + }, + { + "const": "*" + } + ] + } + }, + "required": [ + "displayName", + "hash", + "category", + "source" + ], + "additionalProperties": false + }, + "minItems": 1, + "uniqueItems": true + }, + "adventure": { + "$ref": "adventures.json#/properties/adventure" + }, + "adventureData": { + "$ref": "#/$defs/wrappedAdventureBookDataArray" + }, + "monster": { + "$ref": "bestiary/bestiary.json#/properties/monster" + }, + "monsterFluff": { + "$ref": "bestiary/fluff-bestiary.json#/properties/monsterFluff" + }, + "foundryMonster": { + "$ref": "bestiary/foundry.json#/properties/monster" + }, + "legendaryGroup": { + "$ref": "bestiary/legendarygroups.json#/properties/legendaryGroup" + }, + "book": { + "$ref": "books.json#/properties/book" + }, + "bookData": { + "$ref": "#/$defs/wrappedAdventureBookDataArray" + }, + "class": { + "$ref": "class/class.json#/properties/class" + }, + "classFluff": { + "$ref": "class/fluff-class.json#/properties/classFluff" + }, + "foundryClass": { + "$ref": "class/foundry.json#/properties/class" + }, + "subclass": { + "$ref": "class/class.json#/properties/subclass" + }, + "subclassFluff": { + "$ref": "class/fluff-class.json#/properties/subclassFluff" + }, + "foundrySubclass": { + "$ref": "class/foundry.json#/properties/subclass" + }, + "classFeature": { + "$ref": "class/class.json#/properties/classFeature" + }, + "subclassFeature": { + "$ref": "class/class.json#/properties/subclassFeature" + }, + "foundryClassFeature": { + "$ref": "class/foundry.json#/properties/classFeature" + }, + "foundrySubclassFeature": { + "$ref": "class/foundry.json#/properties/subclassFeature" + }, + "spell": { + "$ref": "spells/spells.json#/properties/spell" + }, + "spellFluff": { + "$ref": "spells/fluff-spells.json#/properties/spellFluff" + }, + "roll20Spell": { + "description": "Based on the Roll20 JSON data, example available here: https://app.roll20.net/compendium/dnd5e/Spells:Fireball.json", + "$ref": "spells/roll20.json#/properties/spell" + }, + "foundrySpell": { + "description": "Based on the Foundry VTT spell data, examples available here: https://gitlab.com/foundrynet/dnd5e/-/tree/master/packs/src/spells", + "$ref": "spells/foundry.json#/properties/spell" + }, + "action": { + "$ref": "actions.json#/properties/action" + }, + "item": { + "$ref": "items.json#/properties/item" + }, + "foundryItem": { + "$ref": "foundry-items.json#/properties/item" + }, + "foundryMagicvariant": { + "$ref": "foundry-items.json#/properties/magicvariant" + }, + "itemGroup": { + "$ref": "items.json#/properties/itemGroup" + }, + "baseitem": { + "$ref": "items-base.json#/properties/baseitem" + }, + "itemProperty": { + "$ref": "items-base.json#/properties/itemProperty" + }, + "itemType": { + "$ref": "items-base.json#/properties/itemType" + }, + "itemEntry": { + "$ref": "items-base.json#/properties/itemEntry" + }, + "itemTypeAdditionalEntries": { + "$ref": "items-base.json#/properties/itemTypeAdditionalEntries" + }, + "itemMastery": { + "$ref": "items-base.json#/properties/itemMastery" + }, + "magicvariant": { + "$ref": "magicvariants.json#/properties/magicvariant" + }, + "linkedLootTables": { + "$ref": "magicvariants.json#/properties/linkedLootTables" + }, + "itemFluff": { + "$ref": "fluff-items.json#/properties/itemFluff" + }, + "background": { + "$ref": "backgrounds.json#/properties/background" + }, + "backgroundFeature": { + "$ref": "foundry-backgrounds.json#/properties/backgroundFeature" + }, + "backgroundFluff": { + "$ref": "fluff-backgrounds.json#/properties/backgroundFluff" + }, + "charoption": { + "$ref": "charcreationoptions.json#/properties/charoption" + }, + "charoptionFluff": { + "$ref": "fluff-charcreationoptions.json#/properties/charoptionFluff" + }, + "condition": { + "$ref": "conditionsdiseases.json#/properties/condition" + }, + "conditionFluff": { + "$ref": "fluff-conditionsdiseases.json#/properties/conditionFluff" + }, + "disease": { + "$ref": "conditionsdiseases.json#/properties/disease" + }, + "status": { + "$ref": "conditionsdiseases.json#/properties/status" + }, + "cult": { + "$ref": "cultsboons.json#/properties/cult" + }, + "boon": { + "$ref": "cultsboons.json#/properties/boon" + }, + "deity": { + "$ref": "deities.json#/properties/deity" + }, + "encounter": { + "$ref": "encounters.json#/properties/encounter" + }, + "feat": { + "$ref": "feats.json#/properties/feat" + }, + "featFluff": { + "$ref": "fluff-feats.json#/properties/featFluff" + }, + "foundryFeat": { + "$ref": "foundry-feats.json#/properties/feat" + }, + "language": { + "$ref": "languages.json#/properties/language" + }, + "languageFluff": { + "$ref": "fluff-languages.json#/properties/languageFluff" + }, + "makebrewCreatureTrait": { + "$ref": "makebrew-creature.json#/properties/makebrewCreatureTrait" + }, + "makebrewCreatureAction": { + "$ref": "makebrew-creature.json#/properties/makebrewCreatureAction" + }, + "reducedItemProperty": { + "$ref": "makecards.json#/properties/reducedItemProperty" + }, + "reducedItemType": { + "$ref": "makecards.json#/properties/reducedItemType" + }, + "monsterfeatures": { + "$ref": "monsterfeatures.json#/properties/monsterfeatures" + }, + "name": { + "$ref": "names.json#/properties/name" + }, + "object": { + "$ref": "objects.json#/properties/object" + }, + "objectFluff": { + "$ref": "fluff-objects.json#/properties/objectFluff" + }, + "optionalfeature": { + "$ref": "optionalfeatures.json#/properties/optionalfeature" + }, + "optionalfeatureFluff": { + "$ref": "fluff-optionalfeatures.json#/properties/optionalfeatureFluff" + }, + "psionic": { + "$ref": "psionics.json#/properties/psionic" + }, + "psionicDisciplineFocus": { + "$ref": "foundry-psionics.json#/properties/psionicDisciplineFocus" + }, + "psionicDisciplineActive": { + "$ref": "foundry-psionics.json#/properties/psionicDisciplineActive" + }, + "race": { + "$ref": "races.json#/properties/race" + }, + "subrace": { + "$ref": "races.json#/properties/subrace" + }, + "foundryRace": { + "$ref": "foundry-races.json#/properties/race" + }, + "foundryRaceFeature": { + "$ref": "foundry-races.json#/properties/raceFeature" + }, + "raceFluff": { + "$ref": "fluff-races.json#/properties/raceFluff" + }, + "raceFluffMeta": { + "$ref": "fluff-races.json#/properties/raceFluffMeta" + }, + "recipe": { + "$ref": "recipes.json#/properties/recipe" + }, + "recipeFluff": { + "$ref": "fluff-recipes.json#/properties/recipeFluff" + }, + "reward": { + "$ref": "rewards.json#/properties/reward" + }, + "rewardFluff": { + "$ref": "fluff-rewards.json#/properties/rewardFluff" + }, + "table": { + "$ref": "tables.json#/properties/table" + }, + "trap": { + "$ref": "trapshazards.json#/properties/trap" + }, + "trapFluff": { + "$ref": "fluff-trapshazards.json#/properties/trapFluff" + }, + "hazard": { + "$ref": "trapshazards.json#/properties/hazard" + }, + "hazardFluff": { + "$ref": "fluff-trapshazards.json#/properties/hazardFluff" + }, + "variantrule": { + "$ref": "variantrules.json#/properties/variantrule" + }, + "vehicle": { + "$ref": "vehicles.json#/properties/vehicle" + }, + "vehicleUpgrade": { + "$ref": "vehicles.json#/properties/vehicleUpgrade" + }, + "vehicleFluff": { + "$ref": "fluff-vehicles.json#/properties/vehicleFluff" + }, + "skill": { + "$ref": "skills.json#/properties/skill" + }, + "sense": { + "$ref": "senses.json#/properties/sense" + }, + "spellList": { + "$ref": "#/$defs/spellList" + }, + "deck": { + "$ref": "decks.json#/properties/deck" + }, + "card": { + "$ref": "decks.json#/properties/card" + }, + "citation": { + "$ref": "citations.json#/properties/citation" + } + }, + "additionalProperties": false, + "required": [ + "_meta" + ] +} \ No newline at end of file diff --git a/.github/workflows/validate-brew-json.yml b/.github/workflows/validate-brew-json.yml new file mode 100644 index 0000000..95448ba --- /dev/null +++ b/.github/workflows/validate-brew-json.yml @@ -0,0 +1,14 @@ +name: Validate Homebrew JSON + +on: [pull_request, push] + +jobs: + verify-json-validation: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - name: Validate JSON + uses: docker://orrosenblatt/validate-json-action:latest + env: + INPUT_SCHEMA: /.github/homebrew-schema.json + INPUT_JSONS: /5etools-homebrew/Dungeon Church; Pyora.json \ No newline at end of file