WEB-37789 JSON Schema documentation for additionalProperties not working

don't know why this flag for skipping additionalProperties was needed, it only breaks some features but adds no value
This commit is contained in:
Anton Lobov
2019-03-14 15:11:14 +01:00
parent 7100892902
commit 48d7dbff9c
17 changed files with 65 additions and 37 deletions
@@ -76,7 +76,7 @@ public class JsonSpellcheckerStrategy extends SpellcheckingStrategy {
final JsonPointerPosition position = walker.findPosition(checkable, isName == ThreeState.NO);
if (position == null || position.isEmpty() && isName == ThreeState.NO) return false;
final Collection<JsonSchemaObject> schemas = new JsonSchemaResolver(project, rootSchema, false, position).resolve();
final Collection<JsonSchemaObject> schemas = new JsonSchemaResolver(project, rootSchema, position).resolve();
if (schemas.isEmpty()) return false;
return schemas.stream().anyMatch(s -> s.getProperties().keySet().contains(value)
@@ -281,7 +281,7 @@ class JsonSchemaAnnotatorChecker {
}
final JsonPointerPosition step = JsonPointerPosition.createSingleProperty(name);
final Pair<ThreeState, JsonSchemaObject> pair = doSingleStep(step, schema, true, false);
final Pair<ThreeState, JsonSchemaObject> pair = doSingleStep(step, schema, false);
if (ThreeState.NO.equals(pair.getFirst()) && !set.contains(name)) {
error(JsonBundle.message("json.schema.annotation.not.allowed.property", name), property.getDelegate(),
JsonValidationError.FixableIssueKind.ProhibitedProperty,
@@ -36,7 +36,7 @@ public class JsonSchemaBasedLanguageInjector extends JsonSchemaInjectorBase {
if (walker == null || walker.isName(context) != ThreeState.NO) return null;
final JsonPointerPosition position = walker.findPosition(context, true);
if (position == null || position.isEmpty()) return null;
final Collection<JsonSchemaObject> schemas = new JsonSchemaResolver(project, schemaObject, false, position).resolve();
final Collection<JsonSchemaObject> schemas = new JsonSchemaResolver(project, schemaObject, position).resolve();
if (schemas.size() != 1) return null;
JsonSchemaObject object = schemas.iterator().next();
String injection = object.getLanguageInjection();
@@ -172,7 +172,7 @@ public class JsonSchemaCompletionContributor extends CompletionContributor {
final JsonPointerPosition position = myWalker.findPosition(checkable, isName == ThreeState.NO);
if (position == null || position.isEmpty() && isName == ThreeState.NO) return;
final Collection<JsonSchemaObject> schemas = new JsonSchemaResolver(myProject, myRootSchema, false, position).resolve();
final Collection<JsonSchemaObject> schemas = new JsonSchemaResolver(myProject, myRootSchema, position).resolve();
final Set<String> knownNames = ContainerUtil.newHashSet();
// too long here, refactor further
schemas.forEach(schema -> {
@@ -61,7 +61,7 @@ public class JsonSchemaComplianceChecker {
if (firstProp != null) {
final JsonPointerPosition position = myWalker.findPosition(firstProp.getDelegate(), true);
if (position == null || position.isEmpty()) return;
final MatchResult result = new JsonSchemaResolver(project, myRootSchema, false, position).detailedResolve();
final MatchResult result = new JsonSchemaResolver(project, myRootSchema, position).detailedResolve();
for (JsonValueAdapter value : firstProp.getValues()) {
createWarnings(JsonSchemaAnnotatorChecker.checkByMatchResult(project, value, result, myOptions));
}
@@ -93,7 +93,7 @@ public class JsonSchemaDocumentationProvider implements DocumentationProvider {
position.replaceStep(position.size() - 1, forcedPropName);
}
}
final Collection<JsonSchemaObject> schemas = new JsonSchemaResolver(element.getProject(), rootSchema, true, position).resolve();
final Collection<JsonSchemaObject> schemas = new JsonSchemaResolver(element.getProject(), rootSchema, position).resolve();
String htmlDescription = null;
boolean deprecated = false;
@@ -34,9 +34,7 @@ public class JsonSchemaGotoDeclarationHandler implements GotoDeclarationHandler
if (steps == null) return null;
final JsonSchemaObject schemaObject = service.getSchemaObject(file);
if (schemaObject != null) {
final PsiElement target = new JsonSchemaResolver(sourceElement.getProject(), schemaObject, false, steps)
.findNavigationTarget(((JsonProperty)parent).getValue(),
JsonSchemaService.isSchemaFile(containingFile));
final PsiElement target = new JsonSchemaResolver(sourceElement.getProject(), schemaObject, steps).findNavigationTarget(((JsonProperty)parent).getValue());
if (target != null) {
return new PsiElement[] {target};
}
@@ -45,28 +45,24 @@ import static com.jetbrains.jsonSchema.impl.JsonSchemaAnnotatorChecker.areSchema
public class JsonSchemaResolver {
@NotNull private final Project myProject;
@NotNull private final JsonSchemaObject mySchema;
private final boolean myIsName;
@NotNull private final JsonPointerPosition myPosition;
public JsonSchemaResolver(@NotNull Project project,
@NotNull JsonSchemaObject schema,
boolean isName,
@NotNull JsonPointerPosition position) {
myProject = project;
mySchema = schema;
myIsName = isName;
myPosition = position;
}
public JsonSchemaResolver(@NotNull Project project, @NotNull JsonSchemaObject schema) {
myProject = project;
mySchema = schema;
myIsName = true;
myPosition = new JsonPointerPosition();
}
public MatchResult detailedResolve() {
final JsonSchemaTreeNode node = JsonSchemaVariantsTreeBuilder.buildTree(myProject, mySchema, myPosition, false, !myIsName);
final JsonSchemaTreeNode node = JsonSchemaVariantsTreeBuilder.buildTree(myProject, mySchema, myPosition, false);
return MatchResult.create(node);
}
@@ -82,10 +78,9 @@ public class JsonSchemaResolver {
}
@Nullable
public PsiElement findNavigationTarget(@Nullable final PsiElement element,
boolean acceptAdditionalPropertiesSchema) {
public PsiElement findNavigationTarget(@Nullable final PsiElement element) {
final JsonSchemaTreeNode node = JsonSchemaVariantsTreeBuilder
.buildTree(myProject, mySchema, myPosition, true, acceptAdditionalPropertiesSchema || !myIsName);
.buildTree(myProject, mySchema, myPosition, true);
final JsonSchemaObject schema = selectSchema(node, element, myPosition.isEmpty());
if (schema == null) return null;
VirtualFile file = JsonSchemaService.Impl.get(myProject).resolveSchemaFile(schema);
@@ -39,8 +39,7 @@ public class JsonSchemaVariantsTreeBuilder {
public static JsonSchemaTreeNode buildTree(@NotNull Project project,
@NotNull final JsonSchemaObject schema,
@NotNull final JsonPointerPosition position,
final boolean skipLastExpand,
final boolean acceptAdditional) {
final boolean skipLastExpand) {
final JsonSchemaTreeNode root = new JsonSchemaTreeNode(null, schema);
JsonSchemaService service = JsonSchemaService.Impl.get(project);
expandChildSchema(root, schema, service);
@@ -59,7 +58,7 @@ public class JsonSchemaVariantsTreeBuilder {
node.nothingChild();
continue;
}
final Pair<ThreeState, JsonSchemaObject> pair = doSingleStep(step, node.getSchema(), acceptAdditional, true);
final Pair<ThreeState, JsonSchemaObject> pair = doSingleStep(step, node.getSchema(), true);
if (ThreeState.NO.equals(pair.getFirst())) node.nothingChild();
else if (ThreeState.YES.equals(pair.getFirst())) node.anyChild();
else {
@@ -112,15 +111,14 @@ public class JsonSchemaVariantsTreeBuilder {
@NotNull
public static Pair<ThreeState, JsonSchemaObject> doSingleStep(@NotNull JsonPointerPosition step,
@NotNull JsonSchemaObject parent,
boolean acceptAdditionalPropertiesSchemas,
boolean processAllBranches) {
final String name = step.getFirstName();
if (name != null) {
return propertyStep(name, parent, acceptAdditionalPropertiesSchemas, processAllBranches);
return propertyStep(name, parent, processAllBranches);
} else {
final int index = step.getFirstIndex();
assert index >= 0;
return arrayOrNumericPropertyElementStep(index, parent, acceptAdditionalPropertiesSchemas);
return arrayOrNumericPropertyElementStep(index, parent);
}
}
@@ -384,7 +382,6 @@ public class JsonSchemaVariantsTreeBuilder {
@NotNull
private static Pair<ThreeState, JsonSchemaObject> propertyStep(@NotNull String name,
@NotNull JsonSchemaObject parent,
boolean acceptAdditionalPropertiesSchemas,
boolean processAllBranches) {
final JsonSchemaObject child = parent.getProperties().get(name);
if (child != null) {
@@ -394,13 +391,13 @@ public class JsonSchemaVariantsTreeBuilder {
if (schema != null) {
return Pair.create(ThreeState.UNSURE, schema);
}
if (acceptAdditionalPropertiesSchemas) {
if (parent.getAdditionalPropertiesSchema() != null) {
return Pair.create(ThreeState.UNSURE, parent.getAdditionalPropertiesSchema());
}
if (parent.getAdditionalPropertiesSchema() != null) {
return Pair.create(ThreeState.UNSURE, parent.getAdditionalPropertiesSchema());
}
if (processAllBranches) {
List<IfThenElse> ifThenElseList = parent.getIfThenElse();
if (ifThenElseList != null && processAllBranches) {
if (ifThenElseList != null) {
for (IfThenElse ifThenElse : ifThenElseList) {
// resolve inside V7 if-then-else conditionals
JsonSchemaObject childObject;
@@ -435,8 +432,7 @@ public class JsonSchemaVariantsTreeBuilder {
}
@NotNull
private static Pair<ThreeState, JsonSchemaObject> arrayOrNumericPropertyElementStep(int idx, @NotNull JsonSchemaObject parent,
boolean acceptAdditionalPropertiesSchemas) {
private static Pair<ThreeState, JsonSchemaObject> arrayOrNumericPropertyElementStep(int idx, @NotNull JsonSchemaObject parent) {
if (parent.getItemsSchema() != null) {
return Pair.create(ThreeState.UNSURE, parent.getItemsSchema());
}
@@ -454,7 +450,7 @@ public class JsonSchemaVariantsTreeBuilder {
if (matchingPatternPropertySchema != null) {
return Pair.create(ThreeState.UNSURE, matchingPatternPropertySchema);
}
if (parent.getAdditionalItemsSchema() != null && acceptAdditionalPropertiesSchemas) {
if (parent.getAdditionalItemsSchema() != null) {
return Pair.create(ThreeState.UNSURE, parent.getAdditionalItemsSchema());
}
if (Boolean.FALSE.equals(parent.getAdditionalItemsAllowed())) {
@@ -37,7 +37,7 @@ public class JsonSchemaDeprecationInspection extends JsonSchemaBasedInspectionBa
JsonPointerPosition position = walker.findPosition(o, true);
if (position == null) return;
final MatchResult result = new JsonSchemaResolver(project, schema, false, position).detailedResolve();
final MatchResult result = new JsonSchemaResolver(project, schema, position).detailedResolve();
for (JsonSchemaObject object : result.mySchemas) {
String message = object.getDeprecationMessage();
if (message != null) {
@@ -30,4 +30,8 @@ public class JsonSchemaDocumentationTest extends JsonBySchemaDocumentationBaseTe
public void testHtmlDescription() throws Exception {
doTest(true, "json");
}
public void testAdditionalPropertyDocs() throws Exception {
doTest(true, "json");
}
}
@@ -0,0 +1 @@
<div class='definition'><pre>enabled: boolean</pre></div><div class='content'>some text</div>
@@ -0,0 +1,8 @@
{
"additionalProp": {
"en<caret>abled": true
},
"knownProp": {
"enabled": false
}
}
@@ -0,0 +1,27 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"definitions": {
"option": {
"type": "object",
"properties": {
"enabled": {
"type": "boolean",
"description": "some text"
}
}
}
},
"additionalProperties": {
"type": "object",
"$ref": "#/definitions/option"
},
"properties": {
"knownProp": {
"type": "object",
"$ref": "#/definitions/option",
"title": "title",
"description": "text"
}
}
}
@@ -0,0 +1 @@
<b>enabled</b>: boolean<br/>some text
@@ -51,7 +51,7 @@ public class YamlJsonSchemaDeprecationInspection extends YamlJsonSchemaInspectio
return;
}
final MatchResult result = new JsonSchemaResolver(project, schema, false, position).detailedResolve();
final MatchResult result = new JsonSchemaResolver(project, schema, position).detailedResolve();
for (JsonSchemaObject object : result.mySchemas) {
String message = object.getDeprecationMessage();
if (message != null) {
@@ -33,9 +33,7 @@ public class YamlJsonSchemaGotoDeclarationHandler implements GotoDeclarationHand
if (steps == null) return null;
final JsonSchemaObject schemaObject = service.getSchemaObject(file);
if (schemaObject != null) {
final PsiElement target = new JsonSchemaResolver(sourceElement.getProject(), schemaObject, false, steps)
.findNavigationTarget(literal.getValue(),
JsonSchemaService.isSchemaFile(containingFile));
final PsiElement target = new JsonSchemaResolver(sourceElement.getProject(), schemaObject, steps).findNavigationTarget(literal.getValue());
if (target != null) {
return new PsiElement[] {target};
}