mirror of
https://github.com/swarm-game/swarm.git
synced 2024-09-11 22:58:21 +03:00
Validate scenarios against json schema (#1475)
Closes #1428 Since the authoritative validation of scenario files is actually performed by virtue of `swarm` parsing them, this CI job actually exists to ensure the JSON Schema descriptions are accurate. This is important for two purposes: * Documentation is generated from the JSON Schema files (#1436) * JSON Schema has integration with VS Code and other IDEs # Testing Verified that the schema checker action does indeed work by intentionally pushing an invalid scenario file in f789f81.
This commit is contained in:
parent
09f8aee9fc
commit
bfc0c143b8
28
.github/workflows/scenario-schema.yml
vendored
Normal file
28
.github/workflows/scenario-schema.yml
vendored
Normal file
@ -0,0 +1,28 @@
|
||||
name: JSON schema
|
||||
on:
|
||||
push:
|
||||
paths:
|
||||
- 'data/scenarios/**.yaml'
|
||||
branches:
|
||||
- main
|
||||
pull_request:
|
||||
paths:
|
||||
- 'data/scenarios/**.yaml'
|
||||
branches:
|
||||
- main
|
||||
jobs:
|
||||
validate-scenario-schema:
|
||||
name: Validate scenarios against schema
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v4
|
||||
with:
|
||||
python-version: "3.10"
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install check-jsonschema
|
||||
- run: |
|
||||
scripts/validate-json-schemas.sh
|
@ -356,8 +356,8 @@ robots:
|
||||
- [0, gate]
|
||||
- [10, hinge]
|
||||
- name: sheep
|
||||
description:
|
||||
- meandering livestock
|
||||
description: |
|
||||
meandering livestock
|
||||
display:
|
||||
invisible: false
|
||||
char: '@'
|
||||
|
@ -14,6 +14,7 @@ entities:
|
||||
char: 'Y'
|
||||
description:
|
||||
- Your scooter
|
||||
robots: []
|
||||
world:
|
||||
palette:
|
||||
'x': [grass, null, base]
|
||||
|
29
data/schema/attribute.json
Normal file
29
data/schema/attribute.json
Normal file
@ -0,0 +1,29 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"$id": "https://raw.githubusercontent.com/swarm-game/swarm/main/data/schema/attribute.json",
|
||||
"title": "Scenario-local attributes",
|
||||
"description": "Local attribute definitions",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "Name of attribute"
|
||||
},
|
||||
"fg": {
|
||||
"type": "string",
|
||||
"description": "Foreground color"
|
||||
},
|
||||
"bg": {
|
||||
"type": "string",
|
||||
"description": "Background color"
|
||||
},
|
||||
"style": {
|
||||
"description": "Style properties list",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -4,6 +4,7 @@
|
||||
"title": "Swarm entity combustion",
|
||||
"description": "Properties of combustion",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"ignition": {
|
||||
"default": 0.5,
|
||||
@ -26,7 +27,7 @@
|
||||
},
|
||||
"product": {
|
||||
"default": "ash",
|
||||
"type": "string",
|
||||
"type": ["string", "null"],
|
||||
"description": "What entity, if any, is left over after combustion"
|
||||
}
|
||||
}
|
||||
|
15
data/schema/cosmic-loc.json
Normal file
15
data/schema/cosmic-loc.json
Normal file
@ -0,0 +1,15 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"$id": "https://raw.githubusercontent.com/swarm-game/swarm/main/data/schema/cosmic-loc.json",
|
||||
"title": "Cosmic location",
|
||||
"description": "Planar location plus subworld",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"subworld": {
|
||||
"type": "string",
|
||||
"description": "Name of subworld"
|
||||
},
|
||||
"loc": {"$ref": "./planar-loc.json"}
|
||||
}
|
||||
}
|
@ -4,6 +4,7 @@
|
||||
"title": "Swarm entity display",
|
||||
"description": "How to display an entity or robot in the Swarm game",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"char": {
|
||||
"default": " ",
|
||||
|
@ -7,6 +7,7 @@
|
||||
"items": {
|
||||
"description": "Description of an entity in the Swarm game",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
@ -14,7 +15,7 @@
|
||||
},
|
||||
"display": {
|
||||
"type": "object",
|
||||
"$ref": "https://raw.githubusercontent.com/swarm-game/swarm/main/data/schema/display.json",
|
||||
"$ref": "./display.json",
|
||||
"description": "Display information for the entity."
|
||||
},
|
||||
"plural": {
|
||||
@ -63,7 +64,7 @@
|
||||
},
|
||||
"combustion": {
|
||||
"type": "object",
|
||||
"$ref": "https://raw.githubusercontent.com/swarm-game/swarm/main/data/schema/combustion.json",
|
||||
"$ref": "./combustion.json",
|
||||
"description": "Properties of combustion."
|
||||
},
|
||||
"yields": {
|
||||
|
15
data/schema/explicit-waypoint.json
Normal file
15
data/schema/explicit-waypoint.json
Normal file
@ -0,0 +1,15 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"$id": "https://raw.githubusercontent.com/swarm-game/swarm/main/data/schema/explicit-waypoint.json",
|
||||
"title": "Waypoint",
|
||||
"description": "Explicit waypoint definition",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"name": {
|
||||
"description": "Waypoint name",
|
||||
"type": "string"
|
||||
},
|
||||
"loc": {"$ref": "./planar-loc.json"}
|
||||
}
|
||||
}
|
40
data/schema/objective.json
Normal file
40
data/schema/objective.json
Normal file
@ -0,0 +1,40 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"$id": "https://raw.githubusercontent.com/swarm-game/swarm/main/data/schema/objective.json",
|
||||
"title": "Scenario goals and their prerequisites",
|
||||
"description": "The top-level objectives field contains a list of objectives that must be completed in sequence. Each objective has a goal description and a condition.",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"goal": {
|
||||
"type": "array",
|
||||
"items": [
|
||||
{
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"description": "The goal description as a list of paragraphs that the player can read."
|
||||
},
|
||||
"condition": {
|
||||
"description": "A swarm program that will be hypothetically run each tick to check if the condition is fulfilled.",
|
||||
"type": "string"
|
||||
},
|
||||
"id": {
|
||||
"description": "A short identifier for referencing as a prerequisite",
|
||||
"type": "string"
|
||||
},
|
||||
"optional": {
|
||||
"description": "Whether completion of this objective is required to achieve a 'Win' of the scenario",
|
||||
"type": "boolean"
|
||||
},
|
||||
"hidden": {
|
||||
"description": "Whether this goal should be suppressed from the Goals dialog prior to achieving it",
|
||||
"type": "boolean"
|
||||
},
|
||||
"teaser": {
|
||||
"description": "A compact (2-3 word) summary of the goal",
|
||||
"type": "string"
|
||||
},
|
||||
"prerequisite": {}
|
||||
}
|
||||
}
|
30
data/schema/placement.json
Normal file
30
data/schema/placement.json
Normal file
@ -0,0 +1,30 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"$id": "https://raw.githubusercontent.com/swarm-game/swarm/main/data/schema/placement.json",
|
||||
"title": "Swarm structure placement",
|
||||
"description": "Structure placement",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"src": {
|
||||
"type": "string",
|
||||
"description": "Name of structure definition"
|
||||
},
|
||||
"offset": {
|
||||
"$ref": "./planar-loc.json"
|
||||
},
|
||||
"orient": {
|
||||
"description": "Orientation of structure",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"up": {
|
||||
"type": "string"
|
||||
},
|
||||
"flip": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
17
data/schema/planar-loc.json
Normal file
17
data/schema/planar-loc.json
Normal file
@ -0,0 +1,17 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"$id": "https://raw.githubusercontent.com/swarm-game/swarm/main/data/schema/planar-loc.json",
|
||||
"title": "Planar location",
|
||||
"description": "x and y coordinates of a location in a particular world",
|
||||
"type": "array",
|
||||
"items": [
|
||||
{
|
||||
"name": "X coordinate",
|
||||
"type": "number"
|
||||
},
|
||||
{
|
||||
"name": "Y coordinate",
|
||||
"type": "number"
|
||||
}
|
||||
]
|
||||
}
|
37
data/schema/portal.json
Normal file
37
data/schema/portal.json
Normal file
@ -0,0 +1,37 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"$id": "https://raw.githubusercontent.com/swarm-game/swarm/main/data/schema/portal.json",
|
||||
"title": "Portals",
|
||||
"description": "Portal definition",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"entrance": {
|
||||
"type": "string",
|
||||
"description": "Name of entrance waypoint"
|
||||
},
|
||||
"reorient": {
|
||||
"description": "Passing through this portal changes a robot's orientation",
|
||||
"type": "string"
|
||||
},
|
||||
"consistent": {
|
||||
"description": "Whether this portal is spatially consistent across worlds",
|
||||
"type": "boolean"
|
||||
},
|
||||
"exitInfo": {
|
||||
"description": "Exit definition",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"exit": {
|
||||
"type": "string",
|
||||
"description": "Name of exit waypoint"
|
||||
},
|
||||
"subworldName": {
|
||||
"type": "string",
|
||||
"description": "Name of exit subworld"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -24,18 +24,19 @@
|
||||
]
|
||||
}
|
||||
],
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"in": {
|
||||
"$ref": "https://raw.githubusercontent.com/swarm-game/swarm/main/data/schema/inventory.json",
|
||||
"$ref": "./inventory.json",
|
||||
"description": "A list of ingredients consumed by the recipe. Each ingredient is a tuple consisting of an integer and an entity name, indicating the number of copies of the given entity that are needed."
|
||||
},
|
||||
"out": {
|
||||
"$ref": "https://raw.githubusercontent.com/swarm-game/swarm/main/data/schema/inventory.json",
|
||||
"$ref": "./inventory.json",
|
||||
"description": "A list of outputs produced by the recipe. It is a list of [count, entity name] tuples just like in."
|
||||
},
|
||||
"required": {
|
||||
"default": [],
|
||||
"$ref": "https://raw.githubusercontent.com/swarm-game/swarm/main/data/schema/inventory.json",
|
||||
"$ref": "./inventory.json",
|
||||
"description": "A list of catalysts required by the recipe. They are neither consumed nor produced, but must be present in order for the recipe to be carried out. It is a list of [count, entity name] tuples just like in and out."
|
||||
},
|
||||
"time": {
|
||||
|
@ -4,6 +4,7 @@
|
||||
"title": "Swarm robot",
|
||||
"description": "Description of a robot in the Swarm game",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
@ -15,19 +16,11 @@
|
||||
"description": "A description of the robot, given as a list of paragraphs. This is currently not used for much (perhaps not at all?)."
|
||||
},
|
||||
"loc": {
|
||||
"default": null,
|
||||
"type": "array",
|
||||
"items": [
|
||||
{
|
||||
"name": "X coordinate",
|
||||
"type": "number"
|
||||
},
|
||||
{
|
||||
"name": "Y coordinate",
|
||||
"type": "number"
|
||||
}
|
||||
],
|
||||
"description": "An optional (x,y) starting location for the robot. If the loc field is specified, then a concrete robot will be created at the given location. If this field is omitted, then this robot record exists only as a template which can be referenced from a cell in the world palette. Concrete robots will then be created wherever the corresponding palette character is used in the world map."
|
||||
"description": "An optional starting location for the robot. If the loc field is specified, then a concrete robot will be created at the given location. If this field is omitted, then this robot record exists only as a template which can be referenced from a cell in the world palette. Concrete robots will then be created wherever the corresponding palette character is used in the world map.",
|
||||
"oneOf": [
|
||||
{"$ref": "./cosmic-loc.json"},
|
||||
{"$ref": "./planar-loc.json"}
|
||||
]
|
||||
},
|
||||
"dir": {
|
||||
"type": "array",
|
||||
@ -46,7 +39,7 @@
|
||||
},
|
||||
"display": {
|
||||
"default": "default",
|
||||
"$ref": "https://raw.githubusercontent.com/swarm-game/swarm/main/data/schema/display.json",
|
||||
"$ref": "./display.json",
|
||||
"description": "Display information for the robot. If this field is omitted, the default robot display will be used."
|
||||
},
|
||||
"program": {
|
||||
@ -64,7 +57,7 @@
|
||||
},
|
||||
"inventory": {
|
||||
"default": [],
|
||||
"$ref": "https://raw.githubusercontent.com/swarm-game/swarm/main/data/schema/inventory.json",
|
||||
"$ref": "./inventory.json",
|
||||
"description": "A list of [count, entity name] pairs, specifying the entities in the robot's starting inventory, and the number of each."
|
||||
},
|
||||
"system": {
|
||||
|
@ -4,6 +4,7 @@
|
||||
"title": "Swarm scenario",
|
||||
"description": "Scenario for the swarm game",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"version": {
|
||||
"description": "The version number of the scenario schema. Currently, this should always be 1.",
|
||||
@ -34,12 +35,12 @@
|
||||
"entities": {
|
||||
"description": "An optional list of custom entities, to be used in addition to the built-in entities. See description of Entities.",
|
||||
"default": [],
|
||||
"$ref": "https://raw.githubusercontent.com/swarm-game/swarm/main/data/schema/entities.json"
|
||||
"$ref": "./entities.json"
|
||||
},
|
||||
"recipes": {
|
||||
"description": "An optional list of custom recipes, to be used in addition to the built-in recipes. They can refer to built-in entities as well as custom entities. See description of Recipes.",
|
||||
"default": [],
|
||||
"$ref": "https://raw.githubusercontent.com/swarm-game/swarm/main/data/schema/recipes.json"
|
||||
"$ref": "./recipes.json"
|
||||
},
|
||||
"known": {
|
||||
"description": "A list of names of standard or custom entities which should have the Known property added to them; that is, robots should know what they are without having to scan them.",
|
||||
@ -52,13 +53,34 @@
|
||||
]
|
||||
},
|
||||
"world": {
|
||||
"$ref": "https://raw.githubusercontent.com/swarm-game/swarm/main/data/schema/world.json"
|
||||
"$ref": "./world.json"
|
||||
},
|
||||
"attrs": {
|
||||
"description": "A list of local attribute definitions",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "./attribute.json"
|
||||
}
|
||||
},
|
||||
"subworlds": {
|
||||
"description": "A list of subworld definitions",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "./world.json"
|
||||
}
|
||||
},
|
||||
"structures": {
|
||||
"description": "Structure definitions",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "./structure.json"
|
||||
}
|
||||
},
|
||||
"robots": {
|
||||
"description": "A list of robots that will inhabit the world. See the description of Robots.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "https://raw.githubusercontent.com/swarm-game/swarm/main/data/schema/robot.json"
|
||||
"$ref": "./robot.json"
|
||||
}
|
||||
},
|
||||
"objectives": {
|
||||
@ -66,24 +88,7 @@
|
||||
"default": [],
|
||||
"type": "array",
|
||||
"items": {
|
||||
"name": "objective",
|
||||
"description": "The top-level objectives field contains a list of objectives that must be completed in sequence. Each objective has a goal description and a condition.",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"goal": {
|
||||
"type": "array",
|
||||
"items": [
|
||||
{
|
||||
"type": "string"
|
||||
}
|
||||
],
|
||||
"description": "The goal description as a list of paragraphs that the player can read."
|
||||
},
|
||||
"condition": {
|
||||
"description": "A swarm program that will be hypothetically run each tick to check if the condition is fulfilled.",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
"$ref": "./objective.json"
|
||||
}
|
||||
},
|
||||
"solution": {
|
||||
|
54
data/schema/structure.json
Normal file
54
data/schema/structure.json
Normal file
@ -0,0 +1,54 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"$id": "https://raw.githubusercontent.com/swarm-game/swarm/main/data/schema/structure.json",
|
||||
"title": "Structures",
|
||||
"description": "Structure definitions",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "Name of this substructure"
|
||||
},
|
||||
"structure": {
|
||||
"description": "Structure properties",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"map": {
|
||||
"type": "string",
|
||||
"description": "Cell-based representation of the structure using palette entries"
|
||||
},
|
||||
"mask": {
|
||||
"type": "string",
|
||||
"description": "A speceial palette character that indicates that map cell should be transparent"
|
||||
},
|
||||
"palette": {
|
||||
"description": "Structure properties",
|
||||
"type": "object"
|
||||
},
|
||||
"waypoints": {
|
||||
"description": "Single-location waypoint definitions",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "./explicit-waypoint.json"
|
||||
}
|
||||
},
|
||||
"placements": {
|
||||
"description": "Structure placements",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "./placement.json"
|
||||
}
|
||||
},
|
||||
"structures": {
|
||||
"description": "Nested structure definitions",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -4,7 +4,40 @@
|
||||
"title": "Swarm world",
|
||||
"description": "Description of the world in the Swarm game",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "Name of this subworld"
|
||||
},
|
||||
"default": {
|
||||
"description": "Default world cell content",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"structures": {
|
||||
"description": "Structure definitions",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "./structure.json"
|
||||
}
|
||||
},
|
||||
"placements": {
|
||||
"description": "Structure placements",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "./placement.json"
|
||||
}
|
||||
},
|
||||
"waypoints": {
|
||||
"description": "Single-location waypoint definitions",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "./explicit-waypoint.json"
|
||||
}
|
||||
},
|
||||
"dsl": {
|
||||
"default": null,
|
||||
"type": "string",
|
||||
@ -26,6 +59,13 @@
|
||||
"examples": [{"T": ["grass", "tree"]}],
|
||||
"description": "The palette maps single character keys to tuples representing contents of cells in the world, so that a world containing entities and robots can be drawn graphically. See Cells for the contents of the tuples representing a cell."
|
||||
},
|
||||
"portals": {
|
||||
"description": "A list of portal definitions that reference waypoints.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "./portal.json"
|
||||
}
|
||||
},
|
||||
"map": {
|
||||
"default": "",
|
||||
"type": "string",
|
||||
|
@ -29,6 +29,26 @@ You can get it by:
|
||||
- **TBD** get the VSIX from GitHub releases
|
||||
- **TBD** installing from the VS codium free marketplace
|
||||
|
||||
### YAML schema validation
|
||||
|
||||
To configure YAML editor tabs for schema validation, install the [YAML plugin](https://marketplace.visualstudio.com/items?itemName=redhat.vscode-yaml) and add the following to `.vscode/settings.json` under the workspace root:
|
||||
|
||||
```json
|
||||
{
|
||||
"yaml.schemas": {
|
||||
"data/schema/scenario.json": [
|
||||
"data/scenarios/**/*.yaml"
|
||||
],
|
||||
"data/schema/entities.json": [
|
||||
"data/entities.yaml"
|
||||
],
|
||||
"data/schema/recipes.json": [
|
||||
"data/recipes.yaml"
|
||||
],
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Vim and Neovim
|
||||
|
||||
Currently there is neither highlighting nor LSP support for Vim,
|
||||
|
9
scripts/validate-json-schemas.sh
Executable file
9
scripts/validate-json-schemas.sh
Executable file
@ -0,0 +1,9 @@
|
||||
#!/bin/bash -e
|
||||
|
||||
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
|
||||
cd $SCRIPT_DIR/..
|
||||
|
||||
find data/scenarios -name "*.yaml" -type f -print0 | xargs -0 check-jsonschema --base-uri $(git rev-parse --show-toplevel)/data/schema/scenario.json --schemafile data/schema/scenario.json
|
||||
|
||||
check-jsonschema --base-uri $(git rev-parse --show-toplevel)/data/schema/entities.json --schemafile data/schema/entities.json data/entities.yaml
|
||||
check-jsonschema --base-uri $(git rev-parse --show-toplevel)/data/schema/recipes.json --schemafile data/schema/recipes.json data/recipes.yaml
|
Loading…
Reference in New Issue
Block a user