Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce JSON validation through schemas (remaster of #315) #1809

Closed
wants to merge 18 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 66 additions & 0 deletions src/main/kotlin/json/SchemaProviders.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* Minecraft Dev for IntelliJ
*
* https://minecraftdev.org
*
* Copyright (c) 2021 minecraft-dev
*
* MIT License
*/

package com.demonwav.mcdev.json

import com.demonwav.mcdev.util.mcDomain
import com.demonwav.mcdev.util.mcPath
import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VirtualFile
import com.jetbrains.jsonSchema.extension.JsonSchemaFileProvider
import com.jetbrains.jsonSchema.extension.JsonSchemaProviderFactory
import com.jetbrains.jsonSchema.extension.SchemaType

class SchemaProviderFactory : JsonSchemaProviderFactory {
override fun getProviders(project: Project) =
listOf(
SoundsSchemaProvider(),
PathBasedSchemaProvider("Minecraft Blockstates JSON", "blockstates", "blockstates/"),
PathBasedSchemaProvider("Minecraft Item Model JSON", "model_item", "models/item/"),
PathBasedSchemaProvider("Minecraft Block Model JSON", "model_block", "models/block/"),
PathBasedSchemaProvider("Minecraft Loot Table JSON", "loot_table", "loot_tables/"),
PathBasedSchemaProvider("Minecraft Tag JSON", "tags", "tags/"),
PathBasedSchemaProvider("Minecraft Particle JSON", "particles", "particles/"),
PathBasedSchemaProvider("Minecraft Advancement JSON", "advancement", "advancements/")
)
}

class SoundsSchemaProvider : JsonSchemaFileProvider {
companion object {
val FILE: VirtualFile = JsonSchemaProviderFactory.getResourceFile(
SchemaProviderFactory::class.java,
"/jsonSchemas/sounds.schema.json"
)
}

override fun getName() = "Minecraft Sounds JSON"

override fun isAvailable(file: VirtualFile) = file.mcDomain != null && file.mcPath == "sounds.json"

override fun getSchemaType(): SchemaType = SchemaType.embeddedSchema

override fun getSchemaFile(): VirtualFile = FILE
}

class PathBasedSchemaProvider(name: String, schema: String, private val path: String) : JsonSchemaFileProvider {
private val _name = name
private val file = JsonSchemaProviderFactory.getResourceFile(
SchemaProviderFactory::class.java,
"/jsonSchemas/$schema.schema.json"
)

override fun getName() = this._name

override fun isAvailable(file: VirtualFile) = file.mcDomain != null && file.mcPath?.startsWith(path) == true

override fun getSchemaType(): SchemaType = SchemaType.embeddedSchema

override fun getSchemaFile(): VirtualFile = file
}
4 changes: 4 additions & 0 deletions src/main/resources/META-INF/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -861,6 +861,10 @@
<projectResolve implementation="com.demonwav.mcdev.platform.mcp.vanillagradle.VanillaGradleProjectResolverExtension"/>
</extensions>

<extensions defaultExtensionNs="JavaScript.JsonSchema">
<ProviderFactory implementation="com.demonwav.mcdev.json.SchemaProviderFactory"/>
</extensions>

<applicationListeners>
<listener class="com.demonwav.mcdev.translations.TranslationFileListener"
topic="com.intellij.openapi.vfs.newvfs.BulkFileListener"/>
Expand Down
126 changes: 126 additions & 0 deletions src/main/resources/jsonSchemas/advancement.schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Minecraft Advancement JSON",
"type": "object",
"properties": {
"display": {
"type": "object",
"properties": {
"icon": {
"type": "object",
"properties": {
"item": { "type": "string" },
"nbt": { "type": "string" }
},
"required": [ "item" ]
},
"title": { "$ref": "common.json#/textComponent" },
"frame": {
"anyOf": [
{ "type": "string" },
{ "enum": [ "task", "goal", "challenge" ], "default": "task" }
]
},
"background": { "type": "string" },
"description": { "$ref": "common.json#/textComponent" },
"show_toast": { "type": "boolean" },
"announce_to_chat": { "type": "boolean" },
"hidden": { "type": "boolean" }
},
"required": [ "title", "description", "icon" ]
},
"parent": { "type": "string" },
"criteria": {
"type": "object",
"additionalProperties": { "$ref": "#/definitions/trigger" },
"minProperties": 1
},
"requirements": {
"type": "array",
"items": {
"type": "array",
"items": { "type": "string", "minLength": 1 }
}
},
"rewards": {
"type": "object",
"properties": {
"recipes": {
"type": "array",
"items": { "type": "string", "minLength": 1 }
},
"loot": {
"type": "array",
"items": { "type": "string", "minLength": 1 }
},
"experience": { "type": "integer" },
"function": { "type": "string" }
}
}
},
"require": [ "criteria" ],
"definitions": {
"trigger": {
"type": "object",
"properties": {
"trigger": {
"anyOf": [
{ "type": "string" },
{
"type": "string",
"enum": [
"minecraft:impossible",
"minecraft:bee_nest_destroyed",
"minecraft:bred_animals",
"minecraft:brewed_potion",
"minecraft:changed_dimension",
"minecraft:channeled_lightning",
"minecraft:construct_beacon",
"minecraft:consume_item",
"minecraft:cured_zombie_villager",
"minecraft:effects_changed",
"minecraft:enchanted_item",
"minecraft:enter_block",
"minecraft:entity_hurt_player",
"minecraft:entity_killed_player",
"minecraft:fall_from_height",
"minecraft:filled_bucket",
"minecraft:fishing_rod_hooked",
"minecraft:hero_of_the_village",
"minecraft:inventory_changed",
"minecraft:item_durability_changed",
"minecraft:item_used_on_block",
"minecraft:killed_by_crossbow",
"minecraft:levitation",
"minecraft:lightning_strike",
"minecraft:location",
"minecraft:nether_travel",
"minecraft:placed_block",
"minecraft:player_generates_container_loot",
"minecraft:player_hurt_entity",
"minecraft:player_interacted_with_entity",
"minecraft:player_killed_entity",
"minecraft:recipe_unlocked",
"minecraft:shot_crossbow",
"minecraft:slept_in_bed",
"minecraft:slide_down_block",
"minecraft:started_riding",
"minecraft:summoned_entity",
"minecraft:tame_animal",
"minecraft:target_hit",
"minecraft:thrown_item_picked_up_by_entity",
"minecraft:tick",
"minecraft:used_ender_eye",
"minecraft:used_totem",
"minecraft:using_item",
"minecraft:villager_trade",
"minecraft:voluntary_exile"
]
}
]
}
},
"required": [ "trigger" ]
}
}
}
18 changes: 18 additions & 0 deletions src/main/resources/jsonSchemas/blockstates.schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Minecraft Blockstates JSON",
"oneOf": [
{
"allOf": [
{ "required": [ "forge_marker" ] },
{ "$ref": "blockstates_forge.schema.json" }
]
},
{
"allOf": [
{ "not": { "required": [ "forge_marker" ] } },
{ "$ref": "blockstates_vanilla.schema.json" }
]
}
]
}
31 changes: 31 additions & 0 deletions src/main/resources/jsonSchemas/blockstates_common.schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"title": "Minecraft Blockstates JSON",
"type": "object",
"properties": {
"variants": {
"type": "array",
"items": {
"oneOf": [
{ "type": "string" },
{
"type": "object",
"properties": {
"x": {
"type": "number"
},
"y": {
"type": "number"
},
"uvlock": {
"type": "boolean",
"default": false
}
}
}
]
},
"uniqueItems": true
}
}
}
Loading