diff --git a/json/src/com/jetbrains/jsonSchema/extension/JsonSchemaProjectSelfProviderFactory.java b/json/src/com/jetbrains/jsonSchema/extension/JsonSchemaProjectSelfProviderFactory.java index 40a7dbbd4b80..f9b6cd4c0bd1 100644 --- a/json/src/com/jetbrains/jsonSchema/extension/JsonSchemaProjectSelfProviderFactory.java +++ b/json/src/com/jetbrains/jsonSchema/extension/JsonSchemaProjectSelfProviderFactory.java @@ -16,15 +16,17 @@ import java.util.List; * @author Irina.Chernushina on 2/24/2016. */ public class JsonSchemaProjectSelfProviderFactory implements JsonSchemaProviderFactory { - public static final int TOTAL_PROVIDERS = 2; - public static final String SCHEMA_JSON_FILE_NAME = "schema.json"; - public static final String SCHEMA06_JSON_FILE_NAME = "schema06.json"; + public static final int TOTAL_PROVIDERS = 3; + private static final String SCHEMA_JSON_FILE_NAME = "schema.json"; + private static final String SCHEMA06_JSON_FILE_NAME = "schema06.json"; + private static final String SCHEMA07_JSON_FILE_NAME = "schema07.json"; @NotNull @Override public List getProviders(@NotNull final Project project) { return ContainerUtil.list(new MyJsonSchemaFileProvider(project, SCHEMA_JSON_FILE_NAME), - new MyJsonSchemaFileProvider(project, SCHEMA06_JSON_FILE_NAME)); + new MyJsonSchemaFileProvider(project, SCHEMA06_JSON_FILE_NAME), + new MyJsonSchemaFileProvider(project, SCHEMA07_JSON_FILE_NAME)); } public static class MyJsonSchemaFileProvider implements JsonSchemaFileProvider { @@ -38,6 +40,9 @@ public class JsonSchemaProjectSelfProviderFactory implements JsonSchemaProviderF public boolean isSchemaV6() { return SCHEMA06_JSON_FILE_NAME.equals(myFileName); } + public boolean isSchemaV7() { + return SCHEMA07_JSON_FILE_NAME.equals(myFileName); + } private MyJsonSchemaFileProvider(@NotNull final Project project, @NotNull String fileName) { myProject = project; @@ -55,6 +60,8 @@ public class JsonSchemaProjectSelfProviderFactory implements JsonSchemaProviderF return isSchemaV4(); case SCHEMA_6: return isSchemaV6(); + case SCHEMA_7: + return isSchemaV7(); } throw new NotImplementedError("Unknown schema version: " + schemaVersion); @@ -62,7 +69,7 @@ public class JsonSchemaProjectSelfProviderFactory implements JsonSchemaProviderF @Override public JsonSchemaVersion getSchemaVersion() { - return isSchemaV4() ? JsonSchemaVersion.SCHEMA_4 : JsonSchemaVersion.SCHEMA_6; + return isSchemaV4() ? JsonSchemaVersion.SCHEMA_4 : isSchemaV7() ? JsonSchemaVersion.SCHEMA_7 : JsonSchemaVersion.SCHEMA_6; } @NotNull diff --git a/json/src/com/jetbrains/jsonSchema/impl/JsonCachedValues.java b/json/src/com/jetbrains/jsonSchema/impl/JsonCachedValues.java index 1db48e31570e..b722124bf392 100644 --- a/json/src/com/jetbrains/jsonSchema/impl/JsonCachedValues.java +++ b/json/src/com/jetbrains/jsonSchema/impl/JsonCachedValues.java @@ -25,7 +25,7 @@ public class JsonCachedValues { @Nullable public static JsonSchemaObject getSchemaObject(@NotNull VirtualFile schemaFile, @NotNull Project project) { JsonFileResolver.startFetchingHttpFileIfNeeded(schemaFile); - final PsiFile psiFile = PsiManager.getInstance(project).findFile(schemaFile); + final PsiFile psiFile = resolveFile(schemaFile, project); if (!(psiFile instanceof JsonFile)) return null; return CachedValueProviderOnPsiFile.getOrCompute(psiFile, JsonCachedValues::computeSchemaObject, JSON_OBJECT_CACHE_KEY); @@ -55,11 +55,17 @@ public class JsonCachedValues { @Nullable public static String getSchemaUrlFromSchemaProperty(@NotNull VirtualFile file, @NotNull Project project) { - PsiFile psiFile = PsiManager.getInstance(project).findFile(file); + PsiFile psiFile = resolveFile(file, project); return !(psiFile instanceof JsonFile) ? null : CachedValueProviderOnPsiFile .getOrCompute(psiFile, JsonCachedValues::fetchSchemaUrl, SCHEMA_URL_KEY); } + private static PsiFile resolveFile(@NotNull VirtualFile file, + @NotNull Project project) { + if (!file.isValid()) return null; + return PsiManager.getInstance(project).findFile(file); + } + @Nullable private static String fetchSchemaUrl(@Nullable PsiFile f) { if (!(f instanceof JsonFile)) return null; @@ -78,7 +84,7 @@ public class JsonCachedValues { public static String getSchemaId(@NotNull final VirtualFile schemaFile, @NotNull final Project project) { if (!schemaFile.isValid()) return null; - final PsiFile psiFile = PsiManager.getInstance(project).findFile(schemaFile); + final PsiFile psiFile = resolveFile(schemaFile, project); if (!(psiFile instanceof JsonFile)) return null; return CachedValueProviderOnPsiFile.getOrCompute(psiFile, JsonCachedValues::getSchemaId, SCHEMA_ID_CACHE_KEY); } @@ -110,7 +116,7 @@ public class JsonCachedValues { public static List, String>> getSchemaCatalog(@NotNull final VirtualFile catalog, @NotNull final Project project) { if (!catalog.isValid()) return null; - final PsiFile psiFile = PsiManager.getInstance(project).findFile(catalog); + final PsiFile psiFile = resolveFile(catalog, project); if (!(psiFile instanceof JsonFile)) return null; return CachedValueProviderOnPsiFile.getOrCompute(psiFile, JsonCachedValues::computeSchemaCatalog, SCHEMA_CATALOG_CACHE_KEY); } diff --git a/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaAnnotatorChecker.java b/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaAnnotatorChecker.java index 8986284f3958..23f547dd9691 100644 --- a/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaAnnotatorChecker.java +++ b/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaAnnotatorChecker.java @@ -190,6 +190,33 @@ class JsonSchemaAnnotatorChecker { final JsonSchemaAnnotatorChecker checker = checkByMatchResult(value, result); if (checker == null || checker.isCorrect()) error("Validates against 'not' schema", value.getDelegate()); } + + if (schema.getIf() != null) { + MatchResult result = new JsonSchemaResolver(schema.getIf()).detailedResolve(); + if (result.mySchemas.isEmpty() && result.myExcludingSchemas.isEmpty()) return; + + final JsonSchemaAnnotatorChecker checker = checkByMatchResult(value, result); + if (checker != null) { + if (checker.isCorrect()) { + JsonSchemaObject then = schema.getThen(); + if (then == null) { + error("Validates against 'if' branch but no 'then' branch is present", value.getDelegate()); + } + else { + checkObjectBySchemaRecordErrors(then, value); + } + } + else { + JsonSchemaObject schemaElse = schema.getElse(); + if (schemaElse == null) { + error("Validates counter 'if' branch but no 'else' branch is present", value.getDelegate()); + } + else { + checkObjectBySchemaRecordErrors(schemaElse, value); + } + } + } + } } private void checkObjectBySchemaRecordErrors(@NotNull JsonSchemaObject schema, @NotNull JsonValueAdapter object) { diff --git a/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaCompletionContributor.java b/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaCompletionContributor.java index 9c7a1be97b76..191a31dfc16c 100644 --- a/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaCompletionContributor.java +++ b/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaCompletionContributor.java @@ -32,6 +32,7 @@ import com.intellij.util.containers.ContainerUtil; import com.jetbrains.jsonSchema.extension.JsonLikePsiWalker; import com.jetbrains.jsonSchema.extension.JsonSchemaFileProvider; import com.jetbrains.jsonSchema.extension.SchemaType; +import com.jetbrains.jsonSchema.extension.adapters.JsonObjectValueAdapter; import com.jetbrains.jsonSchema.extension.adapters.JsonPropertyAdapter; import com.jetbrains.jsonSchema.ide.JsonSchemaService; import org.jetbrains.annotations.NotNull; @@ -142,9 +143,8 @@ public class JsonSchemaCompletionContributor extends CompletionContributor { final JsonPropertyAdapter adapter = myWalker.getParentPropertyAdapter(myOriginalPosition); final Map schemaProperties = schema.getProperties(); - schemaProperties.keySet().stream() - .filter(name -> !properties.contains(name) || adapter != null && name.equals(adapter.getName())) - .forEach(name -> addPropertyVariant(name, schemaProperties.get(name), hasValue, insertComma)); + addAllPropertyVariants(insertComma, hasValue, properties, adapter, schemaProperties); + addIfThenElsePropertyNameVariants(schema, insertComma, hasValue, properties, adapter); } else { suggestValues(schema); @@ -156,6 +156,46 @@ public class JsonSchemaCompletionContributor extends CompletionContributor { } } + private void addIfThenElsePropertyNameVariants(@NotNull JsonSchemaObject schema, + boolean insertComma, + boolean hasValue, + @NotNull Collection properties, + @Nullable JsonPropertyAdapter adapter) { + if (schema.getIf() == null) return; + + JsonLikePsiWalker walker = JsonLikePsiWalker.getWalker(myPosition, schema); + JsonPropertyAdapter propertyAdapter = walker == null ? null : walker.getParentPropertyAdapter(myPosition); + if (propertyAdapter == null) return; + + JsonObjectValueAdapter object = propertyAdapter.getParentObject(); + if (object == null) return; + + JsonSchemaAnnotatorChecker checker = new JsonSchemaAnnotatorChecker(); + checker.checkByScheme(object, schema.getIf()); + if (checker.isCorrect()) { + JsonSchemaObject then = schema.getThen(); + if (then != null) { + addAllPropertyVariants(insertComma, hasValue, properties, adapter, then.getProperties()); + } + } + else { + JsonSchemaObject schemaElse = schema.getElse(); + if (schemaElse != null) { + addAllPropertyVariants(insertComma, hasValue, properties, adapter, schemaElse.getProperties()); + } + } + } + + private void addAllPropertyVariants(boolean insertComma, + boolean hasValue, + Collection properties, + JsonPropertyAdapter adapter, + Map schemaProperties) { + schemaProperties.keySet().stream() + .filter(name -> !properties.contains(name) || adapter != null && name.equals(adapter.getName())) + .forEach(name -> addPropertyVariant(name, schemaProperties.get(name), hasValue, insertComma)); + } + private void suggestValues(JsonSchemaObject schema) { suggestValuesForSchemaVariants(schema.getAnyOf()); suggestValuesForSchemaVariants(schema.getOneOf()); diff --git a/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaObject.java b/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaObject.java index 6da6846d797b..ddb912afaa0b 100644 --- a/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaObject.java +++ b/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaObject.java @@ -89,6 +89,9 @@ public class JsonSchemaObject { @Nullable private List myAnyOf; @Nullable private List myOneOf; @Nullable private JsonSchemaObject myNot; + @Nullable private JsonSchemaObject myIf; + @Nullable private JsonSchemaObject myThen; + @Nullable private JsonSchemaObject myElse; private boolean myShouldValidateAgainstJSType; public JsonSchemaObject(@NotNull JsonObject object) { @@ -152,6 +155,9 @@ public class JsonSchemaObject { myAnyOf = copyList(myAnyOf, other.myAnyOf); myOneOf = copyList(myOneOf, other.myOneOf); if (other.myNot != null) myNot = other.myNot; + if (other.myIf != null) myIf = other.myIf; + if (other.myThen != null) myThen = other.myThen; + if (other.myElse != null) myElse = other.myElse; myShouldValidateAgainstJSType |= other.myShouldValidateAgainstJSType; } @@ -500,6 +506,33 @@ public class JsonSchemaObject { myNot = not; } + @Nullable + public JsonSchemaObject getIf() { + return myIf; + } + + public void setIf(@Nullable JsonSchemaObject anIf) { + myIf = anIf; + } + + @Nullable + public JsonSchemaObject getThen() { + return myThen; + } + + public void setThen(@Nullable JsonSchemaObject then) { + myThen = then; + } + + @Nullable + public JsonSchemaObject getElse() { + return myElse; + } + + public void setElse(@Nullable JsonSchemaObject anElse) { + myElse = anElse; + } + @Nullable public List getTypeVariants() { return myTypeVariants; diff --git a/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaReader.java b/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaReader.java index 6c280eb74b8f..ae4f47c76b96 100644 --- a/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaReader.java +++ b/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaReader.java @@ -190,10 +190,43 @@ public class JsonSchemaReader { READERS_MAP.put("anyOf", createContainer((object, members) -> object.setAnyOf(members))); READERS_MAP.put("oneOf", createContainer((object, members) -> object.setOneOf(members))); READERS_MAP.put("not", createNot()); + READERS_MAP.put("if", createIf()); + READERS_MAP.put("then", createThen()); + READERS_MAP.put("else", createElse()); READERS_MAP.put("instanceof", ((element, object, queue) -> object.shouldValidateAgainstJSType())); READERS_MAP.put("typeof", ((element, object, queue) -> object.shouldValidateAgainstJSType())); } + private static MyReader createIf() { + return (element, object, queue) -> { + if (element instanceof JsonObject) { + final JsonSchemaObject ifSchema = new JsonSchemaObject((JsonObject)element); + queue.add(ifSchema); + object.setIf(ifSchema); + } + }; + } + + private static MyReader createThen() { + return (element, object, queue) -> { + if (element instanceof JsonObject) { + final JsonSchemaObject ifSchema = new JsonSchemaObject((JsonObject)element); + queue.add(ifSchema); + object.setThen(ifSchema); + } + }; + } + + private static MyReader createElse() { + return (element, object, queue) -> { + if (element instanceof JsonObject) { + final JsonSchemaObject ifSchema = new JsonSchemaObject((JsonObject)element); + queue.add(ifSchema); + object.setElse(ifSchema); + } + }; + } + private static MyReader createNot() { return (element, object, queue) -> { if (element instanceof JsonObject) { diff --git a/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaVariantsTreeBuilder.java b/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaVariantsTreeBuilder.java index 045dafcbd368..22a11cef1b71 100644 --- a/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaVariantsTreeBuilder.java +++ b/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaVariantsTreeBuilder.java @@ -369,7 +369,8 @@ public class JsonSchemaVariantsTreeBuilder { } private static boolean interestingSchema(@NotNull JsonSchemaObject schema) { - return schema.getAnyOf() != null || schema.getOneOf() != null || schema.getAllOf() != null || schema.getRef() != null; + return schema.getAnyOf() != null || schema.getOneOf() != null || schema.getAllOf() != null || schema.getRef() != null + || schema.getIf() != null; } public static class Step { @@ -450,8 +451,31 @@ public class JsonSchemaVariantsTreeBuilder { if (schema != null) { return Pair.create(ThreeState.UNSURE, schema); } - if (parent.getAdditionalPropertiesSchema() != null && acceptAdditionalPropertiesSchemas) { - return Pair.create(ThreeState.UNSURE, parent.getAdditionalPropertiesSchema()); + if (acceptAdditionalPropertiesSchemas) { + if (parent.getAdditionalPropertiesSchema() != null) { + return Pair.create(ThreeState.UNSURE, parent.getAdditionalPropertiesSchema()); + } + + // resolve inside V7 if-then-else conditionals + if (parent.getIf() != null) { + JsonSchemaObject childObject; + + // NOTE: do not resolve inside 'if' itself - it is just a condition, but not an actual validation! + // only 'then' and 'else' branches provide actual validation sources, but not the 'if' branch + + if (parent.getThen() != null) { + childObject = parent.getThen().getProperties().get(myName); + if (childObject != null) { + return Pair.create(ThreeState.UNSURE, childObject); + } + } + if (parent.getElse() != null) { + childObject = parent.getElse().getProperties().get(myName); + if (childObject != null) { + return Pair.create(ThreeState.UNSURE, childObject); + } + } + } } if (Boolean.FALSE.equals(parent.getAdditionalPropertiesAllowed())) { return Pair.create(ThreeState.NO, null); diff --git a/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaVersion.java b/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaVersion.java index bef8d151346a..26b5e4edb2ac 100644 --- a/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaVersion.java +++ b/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaVersion.java @@ -7,12 +7,15 @@ import org.jetbrains.annotations.Nullable; public enum JsonSchemaVersion { SCHEMA_4, - SCHEMA_6; + SCHEMA_6, + SCHEMA_7; private static final String ourSchemaV4Schema = "http://json-schema.org/draft-04/schema#"; private static final String ourSchemaV4SchemaTrim = "http://json-schema.org/draft-04/schema"; private static final String ourSchemaV6Schema = "http://json-schema.org/draft-06/schema#"; private static final String ourSchemaV6SchemaTrim = "http://json-schema.org/draft-06/schema"; + private static final String ourSchemaV7Schema = "http://json-schema.org/draft-07/schema#"; + private static final String ourSchemaV7SchemaTrim = "http://json-schema.org/draft-07/schema"; @Override public String toString() { @@ -21,6 +24,8 @@ public enum JsonSchemaVersion { return "JSON Schema Version 4"; case SCHEMA_6: return "JSON Schema Version 6"; + case SCHEMA_7: + return "JSON Schema Version 7"; } throw new NotImplementedError("Unknown version: " + this); @@ -36,12 +41,15 @@ public enum JsonSchemaVersion { case ourSchemaV6Schema: case ourSchemaV6SchemaTrim: return SCHEMA_6; + case ourSchemaV7Schema: + case ourSchemaV7SchemaTrim: + return SCHEMA_7; } return null; } public static boolean isSchemaSchemaId(@Nullable String id) { - return ourSchemaV4Schema.equals(id) || ourSchemaV6Schema.equals(id); + return ourSchemaV4Schema.equals(id) || ourSchemaV6Schema.equals(id) || ourSchemaV7Schema.equals(id); } } diff --git a/json/src/jsonSchema/schema07.json b/json/src/jsonSchema/schema07.json new file mode 100644 index 000000000000..5bee90ec141c --- /dev/null +++ b/json/src/jsonSchema/schema07.json @@ -0,0 +1,168 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "http://json-schema.org/draft-07/schema#", + "title": "Core schema meta-schema", + "definitions": { + "schemaArray": { + "type": "array", + "minItems": 1, + "items": { "$ref": "#" } + }, + "nonNegativeInteger": { + "type": "integer", + "minimum": 0 + }, + "nonNegativeIntegerDefault0": { + "allOf": [ + { "$ref": "#/definitions/nonNegativeInteger" }, + { "default": 0 } + ] + }, + "simpleTypes": { + "enum": [ + "array", + "boolean", + "integer", + "null", + "number", + "object", + "string" + ] + }, + "stringArray": { + "type": "array", + "items": { "type": "string" }, + "uniqueItems": true, + "default": [] + } + }, + "type": ["object", "boolean"], + "properties": { + "$id": { + "type": "string", + "format": "uri-reference" + }, + "$schema": { + "type": "string", + "format": "uri" + }, + "$ref": { + "type": "string", + "format": "uri-reference" + }, + "$comment": { + "type": "string" + }, + "title": { + "type": "string" + }, + "description": { + "type": "string" + }, + "default": true, + "readOnly": { + "type": "boolean", + "default": false + }, + "examples": { + "type": "array", + "items": true + }, + "multipleOf": { + "type": "number", + "exclusiveMinimum": 0 + }, + "maximum": { + "type": "number" + }, + "exclusiveMaximum": { + "type": "number" + }, + "minimum": { + "type": "number" + }, + "exclusiveMinimum": { + "type": "number" + }, + "maxLength": { "$ref": "#/definitions/nonNegativeInteger" }, + "minLength": { "$ref": "#/definitions/nonNegativeIntegerDefault0" }, + "pattern": { + "type": "string", + "format": "regex" + }, + "additionalItems": { "$ref": "#" }, + "items": { + "anyOf": [ + { "$ref": "#" }, + { "$ref": "#/definitions/schemaArray" } + ], + "default": true + }, + "maxItems": { "$ref": "#/definitions/nonNegativeInteger" }, + "minItems": { "$ref": "#/definitions/nonNegativeIntegerDefault0" }, + "uniqueItems": { + "type": "boolean", + "default": false + }, + "contains": { "$ref": "#" }, + "maxProperties": { "$ref": "#/definitions/nonNegativeInteger" }, + "minProperties": { "$ref": "#/definitions/nonNegativeIntegerDefault0" }, + "required": { "$ref": "#/definitions/stringArray" }, + "additionalProperties": { "$ref": "#" }, + "definitions": { + "type": "object", + "additionalProperties": { "$ref": "#" }, + "default": {} + }, + "properties": { + "type": "object", + "additionalProperties": { "$ref": "#" }, + "default": {} + }, + "patternProperties": { + "type": "object", + "additionalProperties": { "$ref": "#" }, + "propertyNames": { "format": "regex" }, + "default": {} + }, + "dependencies": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { "$ref": "#" }, + { "$ref": "#/definitions/stringArray" } + ] + } + }, + "propertyNames": { "$ref": "#" }, + "const": true, + "enum": { + "type": "array", + "items": true, + "minItems": 1, + "uniqueItems": true + }, + "type": { + "anyOf": [ + { "$ref": "#/definitions/simpleTypes" }, + { + "type": "array", + "items": { "$ref": "#/definitions/simpleTypes" }, + "minItems": 1, + "uniqueItems": true + } + ] + }, + "format": { "type": "string" }, + "contentMediaType": { "type": "string" }, + "contentEncoding": { "type": "string" }, + "if": {"$ref": "#"}, + "then": {"$ref": "#"}, + "else": {"$ref": "#"}, + "allOf": { "$ref": "#/definitions/schemaArray" }, + "anyOf": { "$ref": "#/definitions/schemaArray" }, + "oneOf": { "$ref": "#/definitions/schemaArray" }, + "not": { "$ref": "#" } + }, + "default": true +} diff --git a/json/tests/test/com/jetbrains/jsonSchema/JsonSchemaHighlightingTest.java b/json/tests/test/com/jetbrains/jsonSchema/JsonSchemaHighlightingTest.java index b870d056fa79..8f6a9730bb1c 100644 --- a/json/tests/test/com/jetbrains/jsonSchema/JsonSchemaHighlightingTest.java +++ b/json/tests/test/com/jetbrains/jsonSchema/JsonSchemaHighlightingTest.java @@ -704,6 +704,44 @@ public class JsonSchemaHighlightingTest extends DaemonAnalyzerTestCase { doTest(schema, "{\"prop\": \"foo\"}"); } + public void testIfThenElseV7() throws Exception { + @Language("JSON") String schema = "{\n" + + " \"if\": {\n" + + " \"properties\": {\n" + + " \"a\": {\n" + + " \"type\": \"string\"\n" + + " }\n" + + " },\n" + + " \"required\": [\"a\"]\n" + + " },\n" + + " \"then\": {\n" + + " \"properties\": {\n" + + " \"b\": {\n" + + " \"type\": \"number\"\n" + + " }\n" + + " },\n" + + " \"required\": [\"b\"]\n" + + " },\n" + + " \"else\": {\n" + + " \"properties\": {\n" + + " \"c\": {\n" + + " \"type\": \"boolean\"\n" + + " }\n" + + " },\n" + + " \"required\": [\"c\"]\n" + + " }\n" + + "}"; + doTest(schema, "{}"); + doTest(schema, "{\"c\": 5}"); + doTest(schema, "{\"c\": true}"); + doTest(schema, "{\"a\": 5, \"b\": 5}"); + doTest(schema, "{\"a\": 5, \"c\": 5}"); + doTest(schema, "{\"a\": 5, \"c\": true}"); + doTest(schema, "{\"a\": \"a\", \"c\": true}"); + doTest(schema, "{\"a\": \"a\", \"b\": true}"); + doTest(schema, "{\"a\": \"a\", \"b\": 5}"); + } + public void testNestedOneOf() throws Exception { @Language("JSON") String schema = "{\"type\":\"object\",\n" + " \"oneOf\": [\n" + diff --git a/json/tests/test/com/jetbrains/jsonSchema/impl/JsonBySchemaCompletionTest.kt b/json/tests/test/com/jetbrains/jsonSchema/impl/JsonBySchemaCompletionTest.kt index 6d82c77f1fd3..d6f4acedbe2e 100644 --- a/json/tests/test/com/jetbrains/jsonSchema/impl/JsonBySchemaCompletionTest.kt +++ b/json/tests/test/com/jetbrains/jsonSchema/impl/JsonBySchemaCompletionTest.kt @@ -2,6 +2,7 @@ package com.jetbrains.jsonSchema.impl import com.intellij.codeInsight.lookup.LookupElementPresentation import com.jetbrains.jsonSchema.JsonSchemaHighlightingTest +import org.intellij.lang.annotations.Language import org.junit.Assert /** @@ -284,4 +285,71 @@ class JsonBySchemaCompletionTest : JsonBySchemaCompletionBaseTest() { vararg variants: String) { testBySchema(schema, text, ".json", *variants) } + + private val ifThenElseSchema: String + get() { + @Suppress("UnnecessaryVariable") + @Language("JSON") val schema = """{ + "if": { + "properties": { + "a": { + "type": "string" + } + }, + "required": ["a"] + }, + "then": { + "properties": { + "b": { + "type": "number", + "description": "Target b description" + } + }, + "required": ["b"] + }, + "else": { + "properties": { + "c": { + "type": "boolean", + "description": "Target c description" + } + }, + "required": ["c"] + } + }""" + return schema + } + + @Throws(Exception::class) + fun testIfThenElseV7EmptyPropName() { + testImpl(ifThenElseSchema, "{}", "\"c\"") + Assert.assertEquals(1, myItems.size.toLong()) + val presentation = LookupElementPresentation() + myItems[0].renderElement(presentation) + Assert.assertEquals("Target c description", presentation.typeText) + } + + @Throws(Exception::class) + fun testIfThenElseV7ThenPropName() { + testImpl(ifThenElseSchema, """{"a": "a", }""", "\"b\"") + Assert.assertEquals(1, myItems.size.toLong()) + val presentation = LookupElementPresentation() + myItems[0].renderElement(presentation) + Assert.assertEquals("Target b description", presentation.typeText) + } + + @Throws(Exception::class) + fun testIfThenElseV7ElsePropName() { + testImpl(ifThenElseSchema, """{"a": 5, }""", "\"c\"") + Assert.assertEquals(1, myItems.size.toLong()) + val presentation = LookupElementPresentation() + myItems[0].renderElement(presentation) + Assert.assertEquals("Target c description", presentation.typeText) + } + + @Throws(Exception::class) + fun testIfThenElseV7ElsePropValue() { + testImpl(ifThenElseSchema, """{"a": 5, "c": }""", "false", "true") + Assert.assertEquals(2, myItems.size.toLong()) + } } diff --git a/platform/build-scripts/groovy/org/jetbrains/intellij/build/CommunityLibraryLicenses.groovy b/platform/build-scripts/groovy/org/jetbrains/intellij/build/CommunityLibraryLicenses.groovy index 65cf1099bd66..4aeba547e045 100644 --- a/platform/build-scripts/groovy/org/jetbrains/intellij/build/CommunityLibraryLicenses.groovy +++ b/platform/build-scripts/groovy/org/jetbrains/intellij/build/CommunityLibraryLicenses.groovy @@ -219,6 +219,9 @@ class CommunityLibraryLicenses { new LibraryLicense(name: "JSON Schema (schema06.json)", attachedTo: "intellij.json", version: "draft-06", license: "Simplified BSD License", licenseUrl: "https://opensource.org/licenses/BSD-2-Clause", url: "http://json-schema.org/draft-06/schema#"), + new LibraryLicense(name: "JSON Schema (schema07.json)", attachedTo: "intellij.json", version: "draft-07", license: "Simplified BSD License", + licenseUrl: "https://opensource.org/licenses/BSD-2-Clause", + url: "http://json-schema.org/draft-07/schema#"), new LibraryLicense(name: "jsoup", libraryName: "jsoup", version: "1.10.3", license: "MIT", url: "http://jsoup.org", licenseUrl: "http://jsoup.org/license"), new LibraryLicense(name: "jsr305", libraryName: "jsr305", version: "snapshot", license: "BSD", url: "http://code.google.com/p/jsr-305/",