mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
json schema annotation: skip property value annotation if the value does not exist
WEB-26231 JSON Schema: IllegalArgumentException when no value is set for property covered with oneOf validation
This commit is contained in:
@@ -65,6 +65,21 @@ public class JsonBySchemaObjectAnnotator implements Annotator {
|
||||
}
|
||||
if (checkIfAlreadyProcessed(holder, firstProp.getDelegate())) return;
|
||||
|
||||
final JsonValueAdapter firstPropValue = firstProp.getValue();
|
||||
if (firstPropValue != null) checkFirstPropValue(element, holder, walker, firstProp, firstPropValue);
|
||||
|
||||
if (firstProp.getParentObject() != null && walker.isTopJsonElement(firstProp.getParentObject().getDelegate().getParent())) {
|
||||
checkRootObject(holder, firstProp.getParentObject(), walker);
|
||||
}
|
||||
if (firstProp.getParentArray() != null && walker.isTopJsonElement(firstProp.getParentArray().getDelegate().getParent())) {
|
||||
checkRootObject(holder, firstProp.getParentArray(), walker);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkFirstPropValue(@NotNull PsiElement element,
|
||||
@NotNull AnnotationHolder holder,
|
||||
JsonLikePsiWalker walker,
|
||||
JsonPropertyAdapter firstProp, JsonValueAdapter firstPropValue) {
|
||||
final List<BySchemaChecker> checkers = new ArrayList<>();
|
||||
JsonSchemaWalker.findSchemasForAnnotation(firstProp.getDelegate(), JsonSchemaWalker.getWalker(element, myRootSchema), new JsonSchemaWalker.CompletionSchemesConsumer() {
|
||||
@Override
|
||||
@@ -74,7 +89,7 @@ public class JsonBySchemaObjectAnnotator implements Annotator {
|
||||
@NotNull List<JsonSchemaWalker.Step> steps) {
|
||||
final BySchemaChecker checker = new BySchemaChecker(walker);
|
||||
final Set<String> validatedProperties = new HashSet<>();
|
||||
checker.checkByScheme(firstProp.getValue(), schema, validatedProperties);
|
||||
checker.checkByScheme(firstPropValue, schema, validatedProperties);
|
||||
checkers.add(checker);
|
||||
}
|
||||
|
||||
@@ -85,7 +100,7 @@ public class JsonBySchemaObjectAnnotator implements Annotator {
|
||||
@NotNull List<JsonSchemaWalker.Step> steps) {
|
||||
final BySchemaChecker checker = new BySchemaChecker(walker);
|
||||
final Set<String> validatedProperties = new HashSet<>();
|
||||
checker.processOneOf(firstProp.getValue(), list, validatedProperties);
|
||||
checker.processOneOf(firstPropValue, list, validatedProperties);
|
||||
checkers.add(checker);
|
||||
}
|
||||
|
||||
@@ -96,7 +111,7 @@ public class JsonBySchemaObjectAnnotator implements Annotator {
|
||||
@NotNull List<JsonSchemaWalker.Step> steps) {
|
||||
final BySchemaChecker checker = new BySchemaChecker(walker);
|
||||
final Set<String> validatedProperties = new HashSet<>();
|
||||
checker.processAnyOf(firstProp.getValue(), list, validatedProperties);
|
||||
checker.processAnyOf(firstPropValue, list, validatedProperties);
|
||||
checkers.add(checker);
|
||||
}
|
||||
}, myRootSchema, mySchemaFile);
|
||||
@@ -118,13 +133,7 @@ public class JsonBySchemaObjectAnnotator implements Annotator {
|
||||
}
|
||||
}
|
||||
|
||||
if (processCheckerResults(holder, checker)) return;
|
||||
if (firstProp.getParentObject() != null && walker.isTopJsonElement(firstProp.getParentObject().getDelegate().getParent())) {
|
||||
checkRootObject(holder, firstProp.getParentObject(), walker);
|
||||
}
|
||||
if (firstProp.getParentArray() != null && walker.isTopJsonElement(firstProp.getParentArray().getDelegate().getParent())) {
|
||||
checkRootObject(holder, firstProp.getParentArray(), walker);
|
||||
}
|
||||
processCheckerResults(holder, checker);
|
||||
}
|
||||
|
||||
private static JsonValueAdapter findTopLevelElement(@NotNull JsonLikePsiWalker walker, @NotNull PsiElement element) {
|
||||
@@ -160,15 +169,13 @@ public class JsonBySchemaObjectAnnotator implements Annotator {
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean processCheckerResults(@NotNull AnnotationHolder holder, BySchemaChecker checker) {
|
||||
private static void processCheckerResults(@NotNull AnnotationHolder holder, BySchemaChecker checker) {
|
||||
if (! checker.isCorrect()) {
|
||||
for (Map.Entry<PsiElement, String> entry : checker.getErrors().entrySet()) {
|
||||
if (checkIfAlreadyProcessed(holder, entry.getKey())) continue;
|
||||
holder.createWarningAnnotation(entry.getKey(), entry.getValue());
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static class BySchemaChecker {
|
||||
@@ -604,7 +611,7 @@ public class JsonBySchemaObjectAnnotator implements Annotator {
|
||||
}
|
||||
}
|
||||
|
||||
private void processOneOf(JsonValueAdapter value, List<JsonSchemaObject> oneOf, Set<String> validatedProperties) {
|
||||
private void processOneOf(@NotNull JsonValueAdapter value, List<JsonSchemaObject> oneOf, Set<String> validatedProperties) {
|
||||
final Map<PsiElement, String> errors = new HashMap<>();
|
||||
int cntCorrect = 0;
|
||||
boolean validatedPropertiesAdded = false;
|
||||
@@ -647,7 +654,7 @@ public class JsonBySchemaObjectAnnotator implements Annotator {
|
||||
return !checker.getErrors().containsKey(value);
|
||||
}
|
||||
|
||||
private void processAnyOf(JsonValueAdapter value, List<JsonSchemaObject> anyOf, Set<String> validatedProperties) {
|
||||
private void processAnyOf(@NotNull JsonValueAdapter value, List<JsonSchemaObject> anyOf, Set<String> validatedProperties) {
|
||||
final Map<PsiElement, String> errors = new HashMap<>();
|
||||
for (JsonSchemaObject object : anyOf) {
|
||||
final BySchemaChecker checker = new BySchemaChecker(myWalker);
|
||||
|
||||
@@ -328,6 +328,12 @@ public class JsonSchemaHighlightingTest extends DaemonAnalyzerTestCase {
|
||||
testImpl(schemaText, inputText);
|
||||
}
|
||||
|
||||
public void testOneOfWithEmptyPropertyValue() throws Exception {
|
||||
String schemaText = FileUtil.loadFile(new File(getTestDataPath() + "/oneOfSchema.json"));
|
||||
String inputText = FileUtil.loadFile(new File(getTestDataPath() + "/oneOfWithEmptyPropertyValue.json"));
|
||||
testImpl(schemaText, inputText);
|
||||
}
|
||||
|
||||
public void testCycledSchema() throws Exception {
|
||||
String schemaText = FileUtil.loadFile(new File(getTestDataPath() + "/cycledSchema.json"));
|
||||
String inputText = FileUtil.loadFile(new File(getTestDataPath() + "/testCycledSchema.json"));
|
||||
|
||||
+31
-12
@@ -19,6 +19,7 @@ import com.intellij.codeInsight.completion.CodeCompletionHandlerBase;
|
||||
import com.intellij.codeInsight.completion.CompletionType;
|
||||
import com.jetbrains.jsonSchema.JsonSchemaHeavyAbstractTest;
|
||||
import com.jetbrains.jsonSchema.JsonSchemaMappingsConfigurationBase;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
@@ -85,7 +86,35 @@ public class JsonBySchemaHeavyCompletionTest extends JsonSchemaHeavyAbstractTest
|
||||
baseInsertTest("insertPropertyName", "testNameWithDefaultStringValueComma");
|
||||
}
|
||||
|
||||
private void baseInsertTest(final String folder, final String testFile) throws Exception {
|
||||
public void testOneOfWithNotFilledPropertyValue() throws Exception {
|
||||
baseCompletionTest("oneOfWithEnumValue", "oneOfWithEmptyPropertyValue", "\"business\"", "\"home\"");
|
||||
}
|
||||
|
||||
private void baseCompletionTest(@SuppressWarnings("SameParameterValue") final String folder,
|
||||
@SuppressWarnings("SameParameterValue") final String testFile, @NotNull String... items) throws Exception {
|
||||
baseTest(folder, testFile, () -> {
|
||||
complete();
|
||||
assertStringItems(items);
|
||||
});
|
||||
}
|
||||
|
||||
private void baseInsertTest(@SuppressWarnings("SameParameterValue") final String folder, final String testFile) throws Exception {
|
||||
baseTest(folder, testFile, () -> {
|
||||
final CodeCompletionHandlerBase handlerBase = new CodeCompletionHandlerBase(CompletionType.BASIC);
|
||||
handlerBase.invokeCompletion(getProject(), getEditor());
|
||||
if (myItems != null) {
|
||||
selectItem(myItems[0]);
|
||||
}
|
||||
try {
|
||||
checkResultByFile("/" + folder + "/" + testFile + "_after.json");
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void baseTest(@NotNull final String folder, @NotNull final String testFile, @NotNull final Runnable checker) throws Exception {
|
||||
skeleton(new Callback() {
|
||||
@Override
|
||||
public void registerSchemes() {
|
||||
@@ -105,17 +134,7 @@ public class JsonBySchemaHeavyCompletionTest extends JsonSchemaHeavyAbstractTest
|
||||
|
||||
@Override
|
||||
public void doCheck() {
|
||||
final CodeCompletionHandlerBase handlerBase = new CodeCompletionHandlerBase(CompletionType.BASIC);
|
||||
handlerBase.invokeCompletion(getProject(), getEditor());
|
||||
if (myItems != null) {
|
||||
selectItem(myItems[0]);
|
||||
}
|
||||
try {
|
||||
checkResultByFile("/" + folder + "/" + testFile + "_after.json");
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
checker.run();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
{
|
||||
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||
|
||||
"definitions": {
|
||||
"address": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"street_address": { "type": "string" },
|
||||
"city": { "type": "string" },
|
||||
"state": { "type": "string" }
|
||||
},
|
||||
"required": ["street_address", "city", "state"]
|
||||
},
|
||||
"office_address": {
|
||||
"properties": {
|
||||
"type": { "enum": [ "business" ] },
|
||||
"building": { "type": "string" }
|
||||
},
|
||||
"required": ["type", "building"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"home_address": {
|
||||
"properties": {
|
||||
"type": { "enum": [ "home" ] },
|
||||
"street_address": { "type": "string" },
|
||||
"city": { "type": "string" },
|
||||
"state": { "type": "string" }
|
||||
},
|
||||
"required": ["type", "street_address", "city", "state"],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"partOne": {
|
||||
"properties": {"one": {"type": "string"}}
|
||||
},
|
||||
"partTwo": {
|
||||
"properties": {"two": {"type": "integer"}}
|
||||
}
|
||||
},
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"client_address": {
|
||||
"oneOf": [
|
||||
{ "$ref": "#/definitions/office_address" },
|
||||
{ "$ref": "#/definitions/home_address" }
|
||||
]
|
||||
},
|
||||
"parts": {
|
||||
"oneOf": [
|
||||
{ "$ref": "#/definitions/partOne" },
|
||||
{ "$ref": "#/definitions/partTwo" }
|
||||
],
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"client_address": {
|
||||
"building": "1",
|
||||
"type":<caret>
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"client_address": {
|
||||
"building": "1",
|
||||
"type":<EOLError descr="<value> expected, got '}'"></EOLError>
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user