mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
WEB-27538 JSON Schema: quick documentation improvements
This commit is contained in:
@@ -22,6 +22,7 @@ import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.codeStyle.CodeStyleManager;
|
||||
import com.intellij.psi.util.PsiUtilCore;
|
||||
import com.intellij.util.Consumer;
|
||||
import com.intellij.util.ObjectUtils;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.jetbrains.jsonSchema.extension.JsonLikePsiWalker;
|
||||
import com.jetbrains.jsonSchema.extension.JsonSchemaFileProvider;
|
||||
@@ -210,13 +211,13 @@ public class JsonSchemaCompletionContributor extends CompletionContributor {
|
||||
}
|
||||
|
||||
private void addPropertyVariant(@NotNull String key, @NotNull JsonSchemaObject jsonSchemaObject, boolean hasValue, boolean insertComma) {
|
||||
final String description = jsonSchemaObject.getDescription();
|
||||
final String title = jsonSchemaObject.getTitle();
|
||||
jsonSchemaObject = ObjectUtils.coalesce(ContainerUtil.getFirstItem(new JsonSchemaResolver(jsonSchemaObject).resolve()),
|
||||
jsonSchemaObject);
|
||||
key = !myWrapInQuotes ? key : StringUtil.wrapWithDoubleQuote(key);
|
||||
LookupElementBuilder builder = LookupElementBuilder.create(key);
|
||||
|
||||
String typeText = StringUtil.isEmpty(title) ? description : title;
|
||||
if (!StringUtil.isEmpty(typeText)) {
|
||||
final String typeText = StringUtil.escapeXml(jsonSchemaObject.getDocumentation(true));
|
||||
if (!StringUtil.isEmptyOrSpaces(typeText)) {
|
||||
builder = builder.withTypeText(typeText, true);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,15 +1,11 @@
|
||||
package com.jetbrains.jsonSchema.impl;
|
||||
|
||||
import com.intellij.json.psi.JsonObject;
|
||||
import com.intellij.json.psi.JsonProperty;
|
||||
import com.intellij.json.psi.JsonStringLiteral;
|
||||
import com.intellij.json.psi.JsonValue;
|
||||
import com.intellij.lang.documentation.DocumentationProvider;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.PsiManager;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.util.ObjectUtils;
|
||||
import com.jetbrains.jsonSchema.extension.JsonLikePsiWalker;
|
||||
import com.jetbrains.jsonSchema.ide.JsonSchemaService;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -23,7 +19,7 @@ public class JsonSchemaDocumentationProvider implements DocumentationProvider {
|
||||
@Nullable
|
||||
@Override
|
||||
public String getQuickNavigateInfo(PsiElement element, PsiElement originalElement) {
|
||||
return null;
|
||||
return findSchemaAndGenerateDoc(element, originalElement, true);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@@ -35,21 +31,24 @@ public class JsonSchemaDocumentationProvider implements DocumentationProvider {
|
||||
@Nullable
|
||||
@Override
|
||||
public String generateDoc(PsiElement element, @Nullable PsiElement originalElement) {
|
||||
return findSchemaAndGenerateDoc(element, originalElement, false);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static String findSchemaAndGenerateDoc(PsiElement element, @Nullable PsiElement originalElement, final boolean preferShort) {
|
||||
element = ObjectUtils.coalesce(originalElement, element);
|
||||
final PsiFile containingFile = element.getContainingFile();
|
||||
if (containingFile == null) return null;
|
||||
final JsonSchemaService service = JsonSchemaService.Impl.get(element.getProject());
|
||||
final JsonSchemaObject rootSchema = service.getSchemaObject(containingFile.getViewProvider().getVirtualFile());
|
||||
if (rootSchema == null) return null;
|
||||
|
||||
if (JsonSchemaService.isSchemaFile(containingFile)) {
|
||||
return generateForJsonSchemaFileType(element);
|
||||
}
|
||||
return generateDoc(element, rootSchema);
|
||||
return generateDoc(element, rootSchema, preferShort);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static String generateDoc(@NotNull final PsiElement element,
|
||||
@NotNull final JsonSchemaObject rootSchema) {
|
||||
@NotNull final JsonSchemaObject rootSchema, final boolean preferShort) {
|
||||
final JsonLikePsiWalker walker = JsonLikePsiWalker.getWalker(element, rootSchema);
|
||||
if (walker == null) return null;
|
||||
|
||||
@@ -59,24 +58,8 @@ public class JsonSchemaDocumentationProvider implements DocumentationProvider {
|
||||
|
||||
final Collection<JsonSchemaObject> schemas = new JsonSchemaResolver(rootSchema, true, position).resolve();
|
||||
|
||||
return schemas.stream().filter(schema -> !StringUtil.isEmptyOrSpaces(schema.getDescription()))
|
||||
.findFirst().map(JsonSchemaObject::getDescription).orElse(null);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static String generateForJsonSchemaFileType(@NotNull PsiElement element) {
|
||||
final JsonProperty jsonProperty =
|
||||
element instanceof JsonProperty ? (JsonProperty)element : PsiTreeUtil.getParentOfType(element, JsonProperty.class);
|
||||
if (jsonProperty != null) {
|
||||
final JsonValue value = jsonProperty.getValue();
|
||||
if (value instanceof JsonObject) {
|
||||
final JsonProperty description = ((JsonObject)value).findProperty("description");
|
||||
if (description != null && description.getValue() instanceof JsonStringLiteral) {
|
||||
return StringUtil.escapeXml(StringUtil.unquoteString(description.getValue().getText()));
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
return StringUtil.escapeXml(schemas.stream().filter(schema -> !StringUtil.isEmptyOrSpaces(schema.getDocumentation(preferShort)))
|
||||
.findFirst().map(schema -> schema.getDocumentation(preferShort)).orElse(null));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
||||
@@ -87,7 +87,7 @@ public class JsonSchemaObject {
|
||||
|
||||
// peer pointer is not merged!
|
||||
public void mergeValues(JsonSchemaObject other) {
|
||||
// we do not copy id, schema, title and description
|
||||
// we do not copy id, schema
|
||||
|
||||
myProperties.putAll(other.myProperties);
|
||||
myDefinitionsMap = copyMap(myDefinitionsMap, other.myDefinitionsMap);
|
||||
@@ -95,6 +95,9 @@ public class JsonSchemaObject {
|
||||
other.myPatternProperties == null ? null : other.myPatternProperties.mySchemasMap);
|
||||
myPatternProperties = map == null ? null : new PatternProperties(map);
|
||||
|
||||
if (!StringUtil.isEmptyOrSpaces(other.myTitle)) {
|
||||
myTitle = other.myTitle;
|
||||
}
|
||||
if (!StringUtil.isEmptyOrSpaces(other.myDescription)) {
|
||||
myDescription = other.myDescription;
|
||||
}
|
||||
@@ -548,6 +551,12 @@ public class JsonSchemaObject {
|
||||
return current;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getDocumentation(final boolean preferShort) {
|
||||
if (preferShort) return StringUtil.isEmptyOrSpaces(myTitle) ? myDescription : myTitle;
|
||||
return StringUtil.isEmptyOrSpaces(myDescription) ? myTitle : myDescription;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
|
||||
@@ -54,6 +54,7 @@ public class JsonSchemaResolver {
|
||||
return MatchResult.create(node);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public Collection<JsonSchemaObject> resolve() {
|
||||
return resolve(false, false, false);
|
||||
}
|
||||
|
||||
@@ -20,8 +20,10 @@ import com.intellij.json.JsonLanguage;
|
||||
import com.intellij.lang.LanguageDocumentation;
|
||||
import com.intellij.lang.documentation.DocumentationProvider;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.util.PsiUtilBase;
|
||||
import com.jetbrains.jsonSchema.impl.JsonSchemaDocumentationProvider;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.junit.Assert;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
@@ -52,7 +54,8 @@ public abstract class JsonBySchemaDocumentationBaseTest extends JsonSchemaHeavyA
|
||||
|
||||
@Override
|
||||
public void doCheck() {
|
||||
PsiElement psiElement = DocumentationManager.getInstance(getProject()).findTargetElement(myEditor, myFile);
|
||||
final PsiElement psiElement = PsiUtilBase.getElementAtCaret(myEditor);
|
||||
Assert.assertNotNull(psiElement);
|
||||
assertDocumentation(psiElement, psiElement, hasDoc);
|
||||
}
|
||||
});
|
||||
@@ -65,6 +68,12 @@ public abstract class JsonBySchemaDocumentationBaseTest extends JsonSchemaHeavyA
|
||||
protected void assertDocumentation(@NotNull PsiElement docElement, @NotNull PsiElement context, boolean shouldHaveDoc) {
|
||||
DocumentationProvider documentationProvider = DocumentationManager.getProviderFromElement(context);
|
||||
String inlineDoc = documentationProvider.generateDoc(docElement, context);
|
||||
String quickNavigate = documentationProvider.getQuickNavigateInfo(docElement, context);
|
||||
checkExpectedDoc(shouldHaveDoc, inlineDoc, false);
|
||||
checkExpectedDoc(shouldHaveDoc, quickNavigate, true);
|
||||
}
|
||||
|
||||
private void checkExpectedDoc(boolean shouldHaveDoc, String inlineDoc, boolean preferShort) {
|
||||
if (shouldHaveDoc) {
|
||||
assertNotNull("inline help is null", inlineDoc);
|
||||
}
|
||||
@@ -72,7 +81,7 @@ public abstract class JsonBySchemaDocumentationBaseTest extends JsonSchemaHeavyA
|
||||
assertNull("inline help is not null", inlineDoc);
|
||||
}
|
||||
if (shouldHaveDoc) {
|
||||
assertSameLinesWithFile(getTestDataPath() + "/" + getTestName(true) + ".html", inlineDoc);
|
||||
assertSameLinesWithFile(getTestDataPath() + "/" + getTestName(true) + (preferShort ? "_short.html" : ".html"), inlineDoc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,4 +32,12 @@ public class JsonSchemaDocumentationTest extends JsonBySchemaDocumentationBaseTe
|
||||
public void testCheckEscaping() throws Exception {
|
||||
doTest(true, "json");
|
||||
}
|
||||
|
||||
public void testWithDefinition() throws Exception {
|
||||
doTest(true, "json");
|
||||
}
|
||||
|
||||
public void testWithTitleInDefinition() throws Exception {
|
||||
doTest(true, "json");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package com.jetbrains.jsonSchema.impl;
|
||||
|
||||
import com.intellij.codeInsight.lookup.LookupElementPresentation;
|
||||
import com.jetbrains.jsonSchema.JsonSchemaHighlightingTest;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.junit.Assert;
|
||||
|
||||
/**
|
||||
* @author Irina.Chernushina on 10/1/2015.
|
||||
@@ -157,6 +159,47 @@ public class JsonBySchemaCompletionTest extends JsonBySchemaCompletionBaseTest {
|
||||
testImpl(schema, "{\"null\": <caret>}", "false", "null", "true");
|
||||
}
|
||||
|
||||
public void testDescriptionFromDefinitionInCompletion() throws Exception {
|
||||
final String schema = "{\n" +
|
||||
" \"definitions\": {\n" +
|
||||
" \"target\": {\n" +
|
||||
" \"description\": \"Target description\"\n" +
|
||||
" }\n" +
|
||||
" },\n" +
|
||||
" \"properties\": {\n" +
|
||||
" \"source\": {\n" +
|
||||
" \"$ref\": \"#/definitions/target\"\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
"}";
|
||||
testImpl(schema, "{<caret>}", "\"source\"");
|
||||
Assert.assertEquals(1, myItems.length);
|
||||
final LookupElementPresentation presentation = new LookupElementPresentation();
|
||||
myItems[0].renderElement(presentation);
|
||||
Assert.assertEquals("Target description", presentation.getTypeText());
|
||||
}
|
||||
|
||||
public void testDescriptionFromTitleInCompletion() throws Exception {
|
||||
final String schema = "{\n" +
|
||||
" \"definitions\": {\n" +
|
||||
" \"target\": {\n" +
|
||||
" \"title\": \"Target title\",\n" +
|
||||
" \"description\": \"Target description\"\n" +
|
||||
" }\n" +
|
||||
" },\n" +
|
||||
" \"properties\": {\n" +
|
||||
" \"source\": {\n" +
|
||||
" \"$ref\": \"#/definitions/target\"\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
"}";
|
||||
testImpl(schema, "{<caret>}", "\"source\"");
|
||||
Assert.assertEquals(1, myItems.length);
|
||||
final LookupElementPresentation presentation = new LookupElementPresentation();
|
||||
myItems[0].renderElement(presentation);
|
||||
Assert.assertEquals("Target title", presentation.getTypeText());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private static String parcelShopSchema() {
|
||||
return "{\n" +
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
Disallows /// <reference path=> imports (use ES6-style imports instead)
|
||||
@@ -0,0 +1 @@
|
||||
my second level property description 1
|
||||
@@ -0,0 +1 @@
|
||||
my property description 1
|
||||
@@ -0,0 +1 @@
|
||||
Description found through definition
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"<caret>source": {}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"definitions": {
|
||||
"target": {
|
||||
"description": "Description found through definition"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"source": {
|
||||
"$ref": "#/definitions/target"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
Description found through definition
|
||||
@@ -0,0 +1 @@
|
||||
Description found through definition
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"<caret>source": {}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
{
|
||||
"definitions": {
|
||||
"target": {
|
||||
"title": "Title found through definition",
|
||||
"description": "Description found through definition"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"source": {
|
||||
"$ref": "#/definitions/target"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
Title found through definition
|
||||
Reference in New Issue
Block a user