mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
json schema, improve type error highlighting
IDEA-185072 Kubernetes. Json. Add "type" tip into the inspection error description.
This commit is contained in:
@@ -1,18 +1,4 @@
|
||||
/*
|
||||
* Copyright 2000-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.jetbrains.jsonSchema.impl;
|
||||
|
||||
import com.google.common.base.Predicates;
|
||||
@@ -117,8 +103,20 @@ class JsonSchemaAnnotatorChecker {
|
||||
myErrors.put(holder, error);
|
||||
}
|
||||
|
||||
private void typeError(final @NotNull PsiElement value) {
|
||||
error("Type is not allowed", value);
|
||||
private void typeError(final @NotNull PsiElement value, final @NotNull JsonSchemaType... allowedTypes) {
|
||||
if (allowedTypes.length > 0) {
|
||||
if (allowedTypes.length == 1) {
|
||||
error(String.format("Type is not allowed. Expected: %s.", allowedTypes[0].getName()), value);
|
||||
} else {
|
||||
final String typesText = Arrays.stream(allowedTypes)
|
||||
.map(JsonSchemaType::getName)
|
||||
.sorted(Comparator.naturalOrder())
|
||||
.collect(Collectors.joining(", "));
|
||||
error(String.format("Type is not allowed. Expected one of: %s.", typesText), value);
|
||||
}
|
||||
} else {
|
||||
error("Type is not allowed", value);
|
||||
}
|
||||
myHadTypeError = true;
|
||||
}
|
||||
|
||||
@@ -127,7 +125,7 @@ class JsonSchemaAnnotatorChecker {
|
||||
if (type != null) {
|
||||
JsonSchemaType schemaType = getMatchingSchemaType(schema, type);
|
||||
if (schemaType != null && !schemaType.equals(type)) {
|
||||
typeError(value.getDelegate());
|
||||
typeError(value.getDelegate(), schemaType);
|
||||
}
|
||||
else if (JsonSchemaType._boolean.equals(type)) {
|
||||
checkForEnum(value.getDelegate(), schema);
|
||||
@@ -246,8 +244,9 @@ class JsonSchemaAnnotatorChecker {
|
||||
final JsonSchemaObject schemaObject = JsonSchemaService.Impl.get(object.getProject()).getSchemaObjectForSchemaFile(schemaFile);
|
||||
if (schemaObject == null) return;
|
||||
|
||||
final List<JsonSchemaVariantsTreeBuilder.Step> steps =
|
||||
skipProperties(JsonOriginalPsiWalker.INSTANCE.findPosition(object, false, true));
|
||||
final List<JsonSchemaVariantsTreeBuilder.Step> position = JsonOriginalPsiWalker.INSTANCE.findPosition(object, false, true);
|
||||
if (position == null) return;
|
||||
final List<JsonSchemaVariantsTreeBuilder.Step> steps = skipProperties(position);
|
||||
// !! not root schema, because we validate the schema written in the file itself
|
||||
final MatchResult result = new JsonSchemaResolver(schemaObject, false, steps).detailedResolve();
|
||||
final List<JsonSchemaObject> schemas = new ArrayList<>(result.mySchemas);
|
||||
@@ -301,10 +300,12 @@ class JsonSchemaAnnotatorChecker {
|
||||
private void checkForEnum(PsiElement value, JsonSchemaObject schema) {
|
||||
//enum values + pattern -> don't check enum values
|
||||
if (schema.getEnum() == null || schema.getPattern() != null) return;
|
||||
final JsonLikePsiWalker walker = JsonLikePsiWalker.getWalker(value, schema);
|
||||
if (walker == null) return;
|
||||
final String text = StringUtil.notNullize(value.getText());
|
||||
final List<Object> objects = schema.getEnum();
|
||||
for (Object object : objects) {
|
||||
if (JsonLikePsiWalker.getWalker(value, schema).onlyDoubleQuotesForStringLiterals()) {
|
||||
if (walker.onlyDoubleQuotesForStringLiterals()) {
|
||||
if (object.toString().equalsIgnoreCase(text)) return;
|
||||
}
|
||||
else {
|
||||
@@ -342,13 +343,13 @@ class JsonSchemaAnnotatorChecker {
|
||||
final JsonSchemaType type = JsonSchemaType.getType(value);
|
||||
JsonSchemaObject selected = null;
|
||||
if (type == null) {
|
||||
if (!value.isShouldBeIgnored()) checker.typeError(value.getDelegate());
|
||||
if (!value.isShouldBeIgnored()) checker.typeError(value.getDelegate(), getExpectedTypes(collection));
|
||||
}
|
||||
else {
|
||||
final List<JsonSchemaObject> filtered = collection.stream()
|
||||
.filter(schema -> areSchemaTypesCompatible(schema, type))
|
||||
.collect(Collectors.toList());
|
||||
if (filtered.isEmpty()) checker.typeError(value.getDelegate());
|
||||
if (filtered.isEmpty()) checker.typeError(value.getDelegate(), getExpectedTypes(collection));
|
||||
else {
|
||||
if (isOneOf) {
|
||||
selected = checker.processOneOf(value, filtered);
|
||||
@@ -361,6 +362,21 @@ class JsonSchemaAnnotatorChecker {
|
||||
return Pair.create(selected, checker);
|
||||
}
|
||||
|
||||
private final static JsonSchemaType[] NO_TYPES = new JsonSchemaType[0];
|
||||
private static JsonSchemaType[] getExpectedTypes(final Collection<JsonSchemaObject> schemas) {
|
||||
final List<JsonSchemaType> list = new ArrayList<>();
|
||||
for (JsonSchemaObject schema : schemas) {
|
||||
final JsonSchemaType type = schema.getType();
|
||||
if (type != null) {
|
||||
list.add(type);
|
||||
} else {
|
||||
final List<JsonSchemaType> variants = schema.getTypeVariants();
|
||||
list.addAll(variants);
|
||||
}
|
||||
}
|
||||
return list.isEmpty() ? NO_TYPES : list.toArray(new JsonSchemaType[0]);
|
||||
}
|
||||
|
||||
public static boolean areSchemaTypesCompatible(@NotNull final JsonSchemaObject schema, @NotNull final JsonSchemaType type) {
|
||||
final JsonSchemaType matchingSchemaType = getMatchingSchemaType(schema, type);
|
||||
if (matchingSchemaType != null) return matchingSchemaType.equals(type);
|
||||
|
||||
@@ -1,18 +1,4 @@
|
||||
/*
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.jetbrains.jsonSchema;
|
||||
|
||||
import com.intellij.codeInsight.daemon.DaemonAnalyzerTestCase;
|
||||
@@ -93,7 +79,7 @@ public class JsonSchemaHighlightingTest extends DaemonAnalyzerTestCase {
|
||||
"}");
|
||||
doTest(schema, "{\"prop\": [101, 102]}");
|
||||
doTest(schema, "{\"prop\": [<warning descr=\"Less than a minimum 18\">16</warning>]}");
|
||||
doTest(schema, "{\"prop\": [<warning descr=\"Type is not allowed\">\"test\"</warning>]}");
|
||||
doTest(schema, "{\"prop\": [<warning descr=\"Type is not allowed. Expected: number.\">\"test\"</warning>]}");
|
||||
}
|
||||
|
||||
public void testTopLevelArray() throws Exception {
|
||||
@@ -113,7 +99,7 @@ public class JsonSchemaHighlightingTest extends DaemonAnalyzerTestCase {
|
||||
" \"type\": \"object\", \"properties\": {\"a\": {\"type\": \"number\"}}" +
|
||||
" }\n" +
|
||||
"}";
|
||||
doTest(schema, "[{\"a\": <warning descr=\"Type is not allowed\">true</warning>}]");
|
||||
doTest(schema, "[{\"a\": <warning descr=\"Type is not allowed. Expected: number.\">true</warning>}]");
|
||||
doTest(schema, "[{\"a\": 18}]");
|
||||
}
|
||||
|
||||
@@ -124,7 +110,7 @@ public class JsonSchemaHighlightingTest extends DaemonAnalyzerTestCase {
|
||||
" \"type\": \"number\", \"minimum\": 18" +
|
||||
" }, {\"type\" : \"string\"}]\n" +
|
||||
"}");
|
||||
doTest(schema, "{\"prop\": [101, <warning descr=\"Type is not allowed\">102</warning>]}");
|
||||
doTest(schema, "{\"prop\": [101, <warning descr=\"Type is not allowed. Expected: string.\">102</warning>]}");
|
||||
doTest(schema, "{\"prop\": [101, \"102\"]}");
|
||||
doTest(schema, "{\"prop\": [101, \"102\", \"additional\"]}");
|
||||
|
||||
@@ -181,8 +167,8 @@ public class JsonSchemaHighlightingTest extends DaemonAnalyzerTestCase {
|
||||
"\"office\": {\"$ref\": \"#/definitions/address\"}" +
|
||||
"}}";
|
||||
doTest(schema, "{\"home\": {\"street\": \"Broadway\", \"house\": 11}}");
|
||||
doTest(schema, "{\"home\": {\"street\": \"Broadway\", \"house\": <warning descr=\"Type is not allowed\">\"unknown\"</warning>}," +
|
||||
"\"office\": {\"street\": <warning descr=\"Type is not allowed\">5</warning>}}");
|
||||
doTest(schema, "{\"home\": {\"street\": \"Broadway\", \"house\": <warning descr=\"Type is not allowed. Expected: integer.\">\"unknown\"</warning>}," +
|
||||
"\"office\": {\"street\": <warning descr=\"Type is not allowed. Expected: string.\">5</warning>}}");
|
||||
}
|
||||
|
||||
public void testAdditionalPropertiesAllowed() throws Exception {
|
||||
@@ -199,7 +185,7 @@ public class JsonSchemaHighlightingTest extends DaemonAnalyzerTestCase {
|
||||
public void testAdditionalPropertiesSchema() throws Exception {
|
||||
final String schema = "{\"type\": \"object\", \"properties\": {\"a\": {}}," +
|
||||
"\"additionalProperties\": {\"type\": \"string\"}}";
|
||||
doTest(schema, "{\"a\" : 18, \"b\": \"wall\", \"c\": <warning descr=\"Type is not allowed\">11</warning>}");
|
||||
doTest(schema, "{\"a\" : 18, \"b\": \"wall\", \"c\": <warning descr=\"Type is not allowed. Expected: string.\">11</warning>}");
|
||||
}
|
||||
|
||||
public void testMinMaxProperties() throws Exception {
|
||||
@@ -217,7 +203,7 @@ public class JsonSchemaHighlightingTest extends DaemonAnalyzerTestCase {
|
||||
final String schema = schema("{\"oneOf\": [" + StringUtil.join(subSchemas, ", ") + "]}");
|
||||
doTest(schema, "{\"prop\": \"abc\"}");
|
||||
doTest(schema, "{\"prop\": true}");
|
||||
doTest(schema, "{\"prop\": <warning descr=\"Type is not allowed\">11</warning>}");
|
||||
doTest(schema, "{\"prop\": <warning descr=\"Type is not allowed. Expected one of: boolean, string.\">11</warning>}");
|
||||
}
|
||||
|
||||
@SuppressWarnings("Duplicates")
|
||||
@@ -380,9 +366,9 @@ public class JsonSchemaHighlightingTest extends DaemonAnalyzerTestCase {
|
||||
"}";
|
||||
doTest(schema, "{\n" +
|
||||
" \"Abezjana\": 2,\n" +
|
||||
" \"Auto\": <warning descr=\"Type is not allowed\">\"no\"</warning>,\n" +
|
||||
" \"ABe\": <warning descr=\"Type is not allowed\">22</warning>,\n" +
|
||||
" \"Boloto\": <warning descr=\"Type is not allowed\">2</warning>,\n" +
|
||||
" \"Auto\": <warning descr=\"Type is not allowed. Expected: number.\">\"no\"</warning>,\n" +
|
||||
" \"BAe\": <warning descr=\"Type is not allowed. Expected: boolean.\">22</warning>,\n" +
|
||||
" \"Boloto\": <warning descr=\"Type is not allowed. Expected: boolean.\">2</warning>,\n" +
|
||||
" \"Cyan\": <warning descr=\"Value should be one of: [\\\"test\\\", \\\"em\\\"]\">\"me\"</warning>\n" +
|
||||
"}");
|
||||
}
|
||||
@@ -401,7 +387,7 @@ public class JsonSchemaHighlightingTest extends DaemonAnalyzerTestCase {
|
||||
" }\n" +
|
||||
"}";
|
||||
doTest(schema, "{\n" +
|
||||
" \"p1\": <warning descr=\"Type is not allowed\">1</warning>,\n" +
|
||||
" \"p1\": <warning descr=\"Type is not allowed. Expected: string.\">1</warning>,\n" +
|
||||
" \"p2\": \"3\",\n" +
|
||||
" \"a2\": \"auto!\",\n" +
|
||||
" \"a1\": <warning descr=\"Value should be one of: [\\\"auto!\\\"]\">\"moto!\"</warning>\n" +
|
||||
@@ -466,9 +452,9 @@ public class JsonSchemaHighlightingTest extends DaemonAnalyzerTestCase {
|
||||
"}";
|
||||
doTest(schema, "{\n" +
|
||||
" \"size\": <warning descr=\"Number of properties is greater than 3\">{\n" +
|
||||
" \"a\": <warning descr=\"Type is not allowed\">1</warning>," +
|
||||
" \"a\": <warning descr=\"Type is not allowed. Expected: boolean.\">1</warning>," +
|
||||
" \"b\":3, \"c\": 4, " +
|
||||
"\"a\": <warning descr=\"Type is not allowed\">5</warning>\n" +
|
||||
"\"a\": <warning descr=\"Type is not allowed. Expected: boolean.\">5</warning>\n" +
|
||||
" }</warning>\n" +
|
||||
"}");
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"definitions": {
|
||||
"findMe": <warning descr="Type is not allowed">true</warning>
|
||||
"findMe": <warning descr="Type is not allowed. Expected: integer.">true</warning>
|
||||
}
|
||||
}
|
||||
@@ -2,5 +2,5 @@
|
||||
"aaa": 1,
|
||||
"bbb": true,
|
||||
"s": 1,
|
||||
"ccc": <warning descr="Type is not allowed">"3"</warning>
|
||||
"ccc": <warning descr="Type is not allowed. Expected: integer.">"3"</warning>
|
||||
}
|
||||
Reference in New Issue
Block a user