diff --git a/json/src/com/jetbrains/jsonSchema/extension/JsonLikePsiWalker.java b/json/src/com/jetbrains/jsonSchema/extension/JsonLikePsiWalker.java index 88aaa1140ea1..58cf174b7ead 100644 --- a/json/src/com/jetbrains/jsonSchema/extension/JsonLikePsiWalker.java +++ b/json/src/com/jetbrains/jsonSchema/extension/JsonLikePsiWalker.java @@ -2,6 +2,7 @@ package com.jetbrains.jsonSchema.extension; import com.intellij.openapi.extensions.Extensions; +import com.intellij.openapi.project.Project; import com.intellij.psi.PsiElement; import com.intellij.util.ThreeState; import com.jetbrains.jsonSchema.extension.adapters.JsonPropertyAdapter; @@ -63,4 +64,14 @@ public interface JsonLikePsiWalker { default boolean invokeEnterBeforeObjectAndArray() { return false; } default String getNodeTextForValidation(PsiElement element) { return element.getText(); } + + default QuickFixAdapter getQuickFixAdapter(Project project) { return null; } + interface QuickFixAdapter { + @Nullable PsiElement getPropertyValue(PsiElement property); + @Nullable String getPropertyName(PsiElement property); + @NotNull PsiElement createProperty(@NotNull final String name, @NotNull final String value); + boolean ensureComma(PsiElement backward, PsiElement self, PsiElement newElement); + void removeIfComma(PsiElement forward); + boolean fixWhitespaceBefore(); + } } diff --git a/json/src/com/jetbrains/jsonSchema/impl/JsonOriginalPsiWalker.java b/json/src/com/jetbrains/jsonSchema/impl/JsonOriginalPsiWalker.java index 58c5f516e96c..02079c27d6d1 100644 --- a/json/src/com/jetbrains/jsonSchema/impl/JsonOriginalPsiWalker.java +++ b/json/src/com/jetbrains/jsonSchema/impl/JsonOriginalPsiWalker.java @@ -5,6 +5,7 @@ import com.intellij.codeInsight.completion.CompletionUtil; import com.intellij.json.JsonDialectUtil; import com.intellij.json.JsonElementTypes; import com.intellij.json.psi.*; +import com.intellij.openapi.project.Project; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; @@ -166,4 +167,51 @@ public class JsonOriginalPsiWalker implements JsonLikePsiWalker { public JsonValueAdapter createValueAdapter(@NotNull PsiElement element) { return element instanceof JsonValue ? JsonJsonPropertyAdapter.createAdapterByType((JsonValue)element) : null; } + + @Override + public QuickFixAdapter getQuickFixAdapter(Project project) { + return new QuickFixAdapter() { + private final JsonElementGenerator myGenerator = new JsonElementGenerator(project); + @Nullable + @Override + public PsiElement getPropertyValue(PsiElement property) { + assert property instanceof JsonProperty; + return ((JsonProperty)property).getValue(); + } + + @NotNull + @Override + public String getPropertyName(PsiElement property) { + assert property instanceof JsonProperty; + return ((JsonProperty)property).getName(); + } + + @NotNull + @Override + public PsiElement createProperty(@NotNull String name, @NotNull String value) { + return myGenerator.createProperty(name, value); + } + + @Override + public boolean ensureComma(PsiElement backward, PsiElement self, PsiElement newElement) { + if (backward instanceof JsonProperty) { + self.addAfter(myGenerator.createComma(), backward); + return true; + } + return false; + } + + @Override + public void removeIfComma(PsiElement forward) { + if (forward instanceof LeafPsiElement && ((LeafPsiElement)forward).getElementType() == JsonElementTypes.COMMA) { + forward.delete(); + } + } + + @Override + public boolean fixWhitespaceBefore() { + return true; + } + }; + } } diff --git a/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaComplianceChecker.java b/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaComplianceChecker.java index 3d0c9730959c..156893f2edd2 100644 --- a/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaComplianceChecker.java +++ b/json/src/com/jetbrains/jsonSchema/impl/JsonSchemaComplianceChecker.java @@ -4,7 +4,6 @@ package com.jetbrains.jsonSchema.impl; import com.intellij.codeInspection.LocalInspectionToolSession; import com.intellij.codeInspection.LocalQuickFix; import com.intellij.codeInspection.ProblemsHolder; -import com.intellij.json.psi.JsonFile; import com.intellij.openapi.util.Key; import com.intellij.openapi.util.Ref; import com.intellij.psi.PsiElement; @@ -81,7 +80,7 @@ public class JsonSchemaComplianceChecker { if (checkIfAlreadyProcessed(entry.getKey())) continue; String value = entry.getValue().getMessage(); if (myMessagePrefix != null) value = myMessagePrefix + value; - LocalQuickFix fix = entry.getKey().getContainingFile() instanceof JsonFile ? entry.getValue().createFix() : null; + LocalQuickFix fix = entry.getValue().createFix(myWalker.getQuickFixAdapter(myHolder.getProject())); if (fix == null) { myHolder.registerProblem(entry.getKey(), value); } diff --git a/json/src/com/jetbrains/jsonSchema/impl/JsonValidationError.java b/json/src/com/jetbrains/jsonSchema/impl/JsonValidationError.java index 8b02a56e8424..25ab24a9ac31 100644 --- a/json/src/com/jetbrains/jsonSchema/impl/JsonValidationError.java +++ b/json/src/com/jetbrains/jsonSchema/impl/JsonValidationError.java @@ -3,6 +3,7 @@ package com.jetbrains.jsonSchema.impl; import com.intellij.codeInspection.LocalQuickFix; import com.intellij.util.containers.ContainerUtil; +import com.jetbrains.jsonSchema.extension.JsonLikePsiWalker; import com.jetbrains.jsonSchema.impl.fixes.AddMissingPropertyFix; import com.jetbrains.jsonSchema.impl.fixes.RemoveProhibitedPropertyFix; import com.jetbrains.jsonSchema.impl.fixes.SuggestEnumValuesFix; @@ -108,14 +109,15 @@ public class JsonValidationError { } @Nullable - public LocalQuickFix createFix() { + public LocalQuickFix createFix(@Nullable JsonLikePsiWalker.QuickFixAdapter quickFixAdapter) { + if (quickFixAdapter == null) return null; switch (myFixableIssueKind) { case MissingProperty: - return new AddMissingPropertyFix((MissingMultiplePropsIssueData)myIssueData); + return new AddMissingPropertyFix((MissingMultiplePropsIssueData)myIssueData, quickFixAdapter); case ProhibitedProperty: - return new RemoveProhibitedPropertyFix((ProhibitedPropertyIssueData)myIssueData); + return new RemoveProhibitedPropertyFix((ProhibitedPropertyIssueData)myIssueData, quickFixAdapter); case NonEnumValue: - return new SuggestEnumValuesFix(); + return new SuggestEnumValuesFix(quickFixAdapter); default: return null; } diff --git a/json/src/com/jetbrains/jsonSchema/impl/fixes/AddMissingPropertyFix.java b/json/src/com/jetbrains/jsonSchema/impl/fixes/AddMissingPropertyFix.java index c1cc567bc235..cafc032a9bd4 100644 --- a/json/src/com/jetbrains/jsonSchema/impl/fixes/AddMissingPropertyFix.java +++ b/json/src/com/jetbrains/jsonSchema/impl/fixes/AddMissingPropertyFix.java @@ -8,10 +8,6 @@ import com.intellij.codeInsight.template.impl.ConstantNode; import com.intellij.codeInsight.template.impl.MacroCallNode; import com.intellij.codeInsight.template.macro.CompleteMacro; import com.intellij.codeInspection.*; -import com.intellij.json.psi.JsonElementGenerator; -import com.intellij.json.psi.JsonObject; -import com.intellij.json.psi.JsonProperty; -import com.intellij.json.psi.JsonValue; import com.intellij.openapi.application.WriteAction; import com.intellij.openapi.editor.ex.EditorEx; import com.intellij.openapi.editor.ex.util.EditorUtil; @@ -25,6 +21,7 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.DocumentUtil; import com.intellij.util.containers.ContainerUtil; +import com.jetbrains.jsonSchema.extension.JsonLikePsiWalker; import com.jetbrains.jsonSchema.impl.JsonSchemaType; import com.jetbrains.jsonSchema.impl.JsonValidationError; import org.jetbrains.annotations.Nls; @@ -35,9 +32,12 @@ import java.util.List; public class AddMissingPropertyFix implements LocalQuickFix, BatchQuickFix { private final JsonValidationError.MissingMultiplePropsIssueData myData; + private final JsonLikePsiWalker.QuickFixAdapter myQuickFixAdapter; - public AddMissingPropertyFix(JsonValidationError.MissingMultiplePropsIssueData data) { + public AddMissingPropertyFix(JsonValidationError.MissingMultiplePropsIssueData data, + JsonLikePsiWalker.QuickFixAdapter quickFixAdapter) { myData = data; + myQuickFixAdapter = quickFixAdapter; } @Nls(capitalization = Nls.Capitalization.Sentence) @@ -58,17 +58,16 @@ public class AddMissingPropertyFix implements LocalQuickFix, BatchQuickFix hadComma = Ref.create(false); - if (!(element instanceof JsonObject)) return; - PsiElement newElement = performFix(project, element, hadComma); + PsiElement newElement = performFix(element, hadComma); // if we have more than one property, don't expand templates and don't move the caret if (newElement == null) return; - JsonValue value = ((JsonProperty)newElement).getValue(); + PsiElement value = myQuickFixAdapter.getPropertyValue(newElement); FileEditor fileEditor = FileEditorManager.getInstance(project).getSelectedEditor(element.getContainingFile().getVirtualFile()); EditorEx editor = EditorUtil.getEditorEx(fileEditor); assert editor != null; if (value == null) { - WriteAction.run(() ->editor.getCaretModel().moveToOffset(newElement.getTextRange().getEndOffset())); + WriteAction.run(() -> editor.getCaretModel().moveToOffset(newElement.getTextRange().getEndOffset())); return; } TemplateManager templateManager = TemplateManager.getInstance(project); @@ -86,9 +85,7 @@ public class AddMissingPropertyFix implements LocalQuickFix, BatchQuickFix hadComma) { - JsonElementGenerator generator = new JsonElementGenerator(project); - + private PsiElement performFix(PsiElement element, Ref hadComma) { Ref newElementRef = Ref.create(null); WriteAction.run(() -> { @@ -98,19 +95,14 @@ public class AddMissingPropertyFix implements LocalQuickFix, BatchQuickFix propFixes.forEach(fix -> - fix.first.performFix(project, fix.second, Ref.create(false)))); + fix.first.performFix(fix.second, Ref.create(false)))); } @Nullable diff --git a/json/src/com/jetbrains/jsonSchema/impl/fixes/RemoveProhibitedPropertyFix.java b/json/src/com/jetbrains/jsonSchema/impl/fixes/RemoveProhibitedPropertyFix.java index 21200c87d916..fb211e4c98b2 100644 --- a/json/src/com/jetbrains/jsonSchema/impl/fixes/RemoveProhibitedPropertyFix.java +++ b/json/src/com/jetbrains/jsonSchema/impl/fixes/RemoveProhibitedPropertyFix.java @@ -3,21 +3,22 @@ package com.jetbrains.jsonSchema.impl.fixes; import com.intellij.codeInspection.LocalQuickFix; import com.intellij.codeInspection.ProblemDescriptor; -import com.intellij.json.JsonElementTypes; -import com.intellij.json.psi.JsonProperty; import com.intellij.openapi.project.Project; import com.intellij.psi.PsiElement; -import com.intellij.psi.impl.source.tree.LeafPsiElement; import com.intellij.psi.util.PsiTreeUtil; +import com.jetbrains.jsonSchema.extension.JsonLikePsiWalker; import com.jetbrains.jsonSchema.impl.JsonValidationError; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; public class RemoveProhibitedPropertyFix implements LocalQuickFix { private final JsonValidationError.ProhibitedPropertyIssueData myData; + private final JsonLikePsiWalker.QuickFixAdapter myQuickFixAdapter; - public RemoveProhibitedPropertyFix(JsonValidationError.ProhibitedPropertyIssueData data) { + public RemoveProhibitedPropertyFix(JsonValidationError.ProhibitedPropertyIssueData data, + JsonLikePsiWalker.QuickFixAdapter quickFixAdapter) { myData = data; + myQuickFixAdapter = quickFixAdapter; } @Nls(capitalization = Nls.Capitalization.Sentence) @@ -37,12 +38,9 @@ public class RemoveProhibitedPropertyFix implements LocalQuickFix { @Override public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { PsiElement element = descriptor.getPsiElement(); - if (!(element instanceof JsonProperty)) return; - assert myData.propertyName.equals(((JsonProperty)element).getName()); + assert myData.propertyName.equals(myQuickFixAdapter.getPropertyName(element)); PsiElement forward = PsiTreeUtil.skipWhitespacesForward(element); element.delete(); - if (forward instanceof LeafPsiElement && ((LeafPsiElement)forward).getElementType() == JsonElementTypes.COMMA) { - forward.delete(); - } + myQuickFixAdapter.removeIfComma(forward); } } diff --git a/json/src/com/jetbrains/jsonSchema/impl/fixes/SuggestEnumValuesFix.java b/json/src/com/jetbrains/jsonSchema/impl/fixes/SuggestEnumValuesFix.java index ec87708f4c0d..a7a14560f3a6 100644 --- a/json/src/com/jetbrains/jsonSchema/impl/fixes/SuggestEnumValuesFix.java +++ b/json/src/com/jetbrains/jsonSchema/impl/fixes/SuggestEnumValuesFix.java @@ -8,7 +8,6 @@ import com.intellij.codeInspection.BatchQuickFix; import com.intellij.codeInspection.CommonProblemDescriptor; import com.intellij.codeInspection.LocalQuickFix; import com.intellij.codeInspection.ProblemDescriptor; -import com.intellij.json.psi.JsonValue; import com.intellij.openapi.application.WriteAction; import com.intellij.openapi.editor.Editor; import com.intellij.openapi.editor.ex.EditorEx; @@ -19,6 +18,7 @@ import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.Messages; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiWhiteSpace; +import com.jetbrains.jsonSchema.extension.JsonLikePsiWalker; import org.jetbrains.annotations.Nls; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -26,7 +26,10 @@ import org.jetbrains.annotations.Nullable; import java.util.List; public class SuggestEnumValuesFix implements LocalQuickFix, BatchQuickFix { - public SuggestEnumValuesFix() { + private final JsonLikePsiWalker.QuickFixAdapter myQuickFixAdapter; + + public SuggestEnumValuesFix(JsonLikePsiWalker.QuickFixAdapter quickFixAdapter) { + myQuickFixAdapter = quickFixAdapter; } @Nls(capitalization = Nls.Capitalization.Sentence) @@ -46,7 +49,6 @@ public class SuggestEnumValuesFix implements LocalQuickFix, BatchQuickFix element.delete()); EditorEx editor = EditorUtil.getEditorEx(fileEditor); assert editor != null; - if (whitespaceBefore) { + if (myQuickFixAdapter.fixWhitespaceBefore() && whitespaceBefore) { WriteAction.run(() -> { int offset = editor.getCaretModel().getOffset(); editor.getDocument().insertString(offset, " "); diff --git a/json/tests/test/com/jetbrains/jsonSchema/JsonSchemaHighlightingTestBase.java b/json/tests/test/com/jetbrains/jsonSchema/JsonSchemaHighlightingTestBase.java index eacdf3d5254a..89db6b4c4f87 100644 --- a/json/tests/test/com/jetbrains/jsonSchema/JsonSchemaHighlightingTestBase.java +++ b/json/tests/test/com/jetbrains/jsonSchema/JsonSchemaHighlightingTestBase.java @@ -26,9 +26,16 @@ public abstract class JsonSchemaHighlightingTestBase extends DaemonAnalyzerTestC protected abstract Predicate getAvailabilityPredicate(); protected void doTest(@Language("JSON") @NotNull final String schema, @NotNull final String text) throws Exception { + final PsiFile file = configureInitially(schema, text); + doTest(file.getVirtualFile(), true, false); + } + + @NotNull + protected PsiFile configureInitially(@NotNull @Language("JSON") String schema, + @NotNull String text) throws Exception { enableInspectionTool(getInspectionProfile()); - final PsiFile file = createFile(myModule, getTestFileName(), text); + final PsiFile file = doCreateFile(text); registerProvider(getProject(), schema); Disposer.register(getTestRootDisposable(), new Disposable() { @@ -38,7 +45,12 @@ public abstract class JsonSchemaHighlightingTestBase extends DaemonAnalyzerTestC } }); configureByFile(file.getVirtualFile()); - doTest(file.getVirtualFile(), true, false); + return file; + } + + @NotNull + protected PsiFile doCreateFile(@NotNull String text) throws Exception { + return createFile(myModule, getTestFileName(), text); } private void registerProvider(Project project, @NotNull String schema) throws IOException { diff --git a/json/tests/test/com/jetbrains/jsonSchema/fixes/JsonSchemaQuickFixTest.java b/json/tests/test/com/jetbrains/jsonSchema/fixes/JsonSchemaQuickFixTest.java new file mode 100644 index 000000000000..fe676da22c69 --- /dev/null +++ b/json/tests/test/com/jetbrains/jsonSchema/fixes/JsonSchemaQuickFixTest.java @@ -0,0 +1,52 @@ +// 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.fixes; + +import com.intellij.codeInspection.InspectionProfileEntry; +import com.intellij.json.JsonLanguage; +import com.intellij.openapi.fileTypes.LanguageFileType; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.containers.Predicate; +import com.jetbrains.jsonSchema.impl.JsonSchemaComplianceInspection; + +public class JsonSchemaQuickFixTest extends JsonSchemaQuickFixTestBase { + @Override + protected String getTestFileName() { + return "config.json"; + } + + @Override + protected InspectionProfileEntry getInspectionProfile() { + return new JsonSchemaComplianceInspection(); + } + + @Override + protected Predicate getAvailabilityPredicate() { + return file -> file.getFileType() instanceof LanguageFileType && ((LanguageFileType)file.getFileType()).getLanguage().isKindOf( + JsonLanguage.INSTANCE); + } + + public void testAddMissingProperty() throws Exception { + doTest("{\n" + + " \"properties\": {\n" + + " \"a\": {\n" + + " \"default\": \"q\"\n" + + " }\n" + + " },\n" + + " \"required\": [\"a\", \"b\"]\n" + + "}", "{\"c\": 5}", "Add missing properties 'a', 'b'", "{\"c\": 5,\n" + + " \"a\": \"q\",\n" + + " \"b\":\n" + + "}"); + } + + public void testRemoveProhibitedProperty() throws Exception { + doTest("{\n" + + " \"properties\": {\n" + + " \"a\": {},\n" + + " \"c\": {}\n" + + " },\n" + + " \"additionalProperties\": false\n" + + "}", "{\"a\": 5, \"b\": 6, \"c\": 7}", "Remove prohibited property 'b'", "{\"a\": 5,\n" + + " \"c\": 7}"); + } +} diff --git a/json/tests/test/com/jetbrains/jsonSchema/fixes/JsonSchemaQuickFixTestBase.java b/json/tests/test/com/jetbrains/jsonSchema/fixes/JsonSchemaQuickFixTestBase.java new file mode 100644 index 000000000000..6b74111d1b1f --- /dev/null +++ b/json/tests/test/com/jetbrains/jsonSchema/fixes/JsonSchemaQuickFixTestBase.java @@ -0,0 +1,43 @@ +// 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.fixes; + +import com.intellij.codeInsight.EditorInfo; +import com.intellij.codeInsight.daemon.impl.HighlightInfo; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.util.io.FileUtil; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.psi.PsiFile; +import com.jetbrains.jsonSchema.JsonSchemaHighlightingTestBase; +import org.intellij.lang.annotations.Language; +import org.jetbrains.annotations.NotNull; + +import java.io.File; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; + +public abstract class JsonSchemaQuickFixTestBase extends JsonSchemaHighlightingTestBase { + protected void doTest(@Language("JSON") @NotNull String schema, @NotNull String text, String fixName, String afterFix) throws Exception { + PsiFile file = configureInitially(schema, text); + HashMap map = new HashMap<>(); + map.put(file.getVirtualFile(), new EditorInfo(file.getText())); + List editors = openEditors(map); + Collection infos = doDoTest(true, false); + PsiFile psiFile = getPsiFile(editors.get(0).getDocument()); + findAndInvokeIntentionAction(infos, fixName, editors.get(0), psiFile); + assertEquals(afterFix, getFile().getText()); + } + + @NotNull + @Override + protected PsiFile doCreateFile(@NotNull String text) throws Exception { + File dir = createTempDir("json_schema_test_r", true); + File child = new File(dir, getTestFileName()); + //noinspection ResultOfMethodCallIgnored + child.createNewFile(); + FileUtil.writeToFile(child, text); + VirtualFile schemaFile = getVirtualFile(child); + schemaFile.setWritable(true); + return getPsiManager().findFile(schemaFile); + } +} diff --git a/json/tests/test/com/jetbrains/jsonSchema/schemaFile/JsonSchemaTestSuite.java b/json/tests/test/com/jetbrains/jsonSchema/schemaFile/JsonSchemaTestSuite.java index 828a46e54df0..59b20ad40793 100644 --- a/json/tests/test/com/jetbrains/jsonSchema/schemaFile/JsonSchemaTestSuite.java +++ b/json/tests/test/com/jetbrains/jsonSchema/schemaFile/JsonSchemaTestSuite.java @@ -16,6 +16,7 @@ package com.jetbrains.jsonSchema.schemaFile; import com.jetbrains.jsonSchema.*; +import com.jetbrains.jsonSchema.fixes.JsonSchemaQuickFixTest; import com.jetbrains.jsonSchema.impl.JsonBySchemaCompletionTest; import com.jetbrains.jsonSchema.impl.JsonBySchemaHeavyCompletionTest; import com.jetbrains.jsonSchema.impl.JsonSchemaReadTest; @@ -40,6 +41,7 @@ public class JsonSchemaTestSuite extends TestCase { suite.addTestSuite(JsonSchemaReadTest.class); suite.addTestSuite(JsonSchemaFileResolveTest.class); suite.addTestSuite(JsonSchemaPerformanceTest.class); + suite.addTestSuite(JsonSchemaQuickFixTest.class); return suite; } } \ No newline at end of file diff --git a/plugins/yaml/src/org/jetbrains/yaml/schema/YamlJsonPsiWalker.java b/plugins/yaml/src/org/jetbrains/yaml/schema/YamlJsonPsiWalker.java index d6b0205ff97f..a99a42c617f1 100644 --- a/plugins/yaml/src/org/jetbrains/yaml/schema/YamlJsonPsiWalker.java +++ b/plugins/yaml/src/org/jetbrains/yaml/schema/YamlJsonPsiWalker.java @@ -2,9 +2,11 @@ package org.jetbrains.yaml.schema; import com.intellij.lang.ASTNode; +import com.intellij.openapi.project.Project; import com.intellij.openapi.util.text.StringUtil; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; +import com.intellij.psi.impl.source.tree.LeafPsiElement; import com.intellij.psi.util.PsiTreeUtil; import com.intellij.util.ThreeState; import com.jetbrains.jsonSchema.extension.JsonLikePsiWalker; @@ -13,6 +15,7 @@ import com.jetbrains.jsonSchema.extension.adapters.JsonValueAdapter; import com.jetbrains.jsonSchema.impl.JsonSchemaVariantsTreeBuilder; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.yaml.YAMLElementGenerator; import org.jetbrains.yaml.YAMLTokenTypes; import org.jetbrains.yaml.psi.*; import org.jetbrains.yaml.psi.impl.YAMLBlockMappingImpl; @@ -202,4 +205,56 @@ public class YamlJsonPsiWalker implements JsonLikePsiWalker { int spaceIndex = text.indexOf(' '); return spaceIndex > 0 ? text.substring(spaceIndex + 1) : text; } + + @Override + public QuickFixAdapter getQuickFixAdapter(Project project) { + return new QuickFixAdapter() { + private final YAMLElementGenerator myGenerator = YAMLElementGenerator.getInstance(project); + + @Nullable + @Override + public PsiElement getPropertyValue(PsiElement property) { + assert property instanceof YAMLKeyValue; + return ((YAMLKeyValue)property).getValue(); + } + + @Nullable + @Override + public String getPropertyName(PsiElement property) { + assert property instanceof YAMLKeyValue; + return ((YAMLKeyValue)property).getName(); + } + + @NotNull + @Override + public PsiElement createProperty(@NotNull String name, @NotNull String value) { + return myGenerator.createYamlKeyValue(name, StringUtil.unquoteString(value)); + } + + @Override + public boolean ensureComma(PsiElement backward, PsiElement self, PsiElement newElement) { + if (newElement instanceof YAMLKeyValue) { + newElement.getParent().addAfter(myGenerator.createEol(), newElement); + } + return false; + } + + @Override + public void removeIfComma(PsiElement forward) { + if (forward instanceof LeafPsiElement && ((LeafPsiElement)forward).getElementType() == YAMLTokenTypes.EOL) { + PsiElement nextSibling; + while ((nextSibling = forward.getNextSibling()) instanceof LeafPsiElement + && ((LeafPsiElement)nextSibling).getElementType() == YAMLTokenTypes.INDENT){ + nextSibling.delete(); + } + forward.delete(); + } + } + + @Override + public boolean fixWhitespaceBefore() { + return false; + } + }; + } } diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/schema/YamlByJsonSchemaQuickFixTest.java b/plugins/yaml/testSrc/org/jetbrains/yaml/schema/YamlByJsonSchemaQuickFixTest.java new file mode 100644 index 000000000000..9a67307ea70e --- /dev/null +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/schema/YamlByJsonSchemaQuickFixTest.java @@ -0,0 +1,51 @@ +// 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 org.jetbrains.yaml.schema; + +import com.intellij.codeInspection.InspectionProfileEntry; +import com.intellij.openapi.fileTypes.LanguageFileType; +import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.util.containers.Predicate; +import com.jetbrains.jsonSchema.fixes.JsonSchemaQuickFixTestBase; +import org.jetbrains.yaml.YAMLLanguage; + +public class YamlByJsonSchemaQuickFixTest extends JsonSchemaQuickFixTestBase { + @Override + protected String getTestFileName() { + return "config.yml"; + } + + @Override + protected InspectionProfileEntry getInspectionProfile() { + return new YamlJsonSchemaHighlightingInspection(); + } + + @Override + protected Predicate getAvailabilityPredicate() { + return file -> file.getFileType() instanceof LanguageFileType && ((LanguageFileType)file.getFileType()).getLanguage().isKindOf( + YAMLLanguage.INSTANCE); + } + + public void testAddMissingProperty() throws Exception { + doTest("{\n" + + " \"properties\": {\n" + + " \"a\": {\n" + + " \"default\": \"q\"\n" + + " }\n" + + " },\n" + + " \"required\": [\"a\", \"b\"]\n" + + "}", "c: 5", "Add missing properties 'a', 'b'", "a: q\n" + + "b:\n" + + "c: 5"); + } + + public void testRemoveProhibitedProperty() throws Exception { + doTest("{\n" + + " \"properties\": {\n" + + " \"a\": {},\n" + + " \"c\": {}\n" + + " },\n" + + " \"additionalProperties\": false\n" + + "}", "a: 5\nb: 6\nc: 7", "Remove prohibited property 'b'", "a: 5\n" + + "c: 7"); + } +} diff --git a/plugins/yaml/testSrc/org/jetbrains/yaml/schema/YamlJsonSchemaTestSuite.java b/plugins/yaml/testSrc/org/jetbrains/yaml/schema/YamlJsonSchemaTestSuite.java index 9bd7b8538500..ea9927e833dc 100644 --- a/plugins/yaml/testSrc/org/jetbrains/yaml/schema/YamlJsonSchemaTestSuite.java +++ b/plugins/yaml/testSrc/org/jetbrains/yaml/schema/YamlJsonSchemaTestSuite.java @@ -13,6 +13,7 @@ public class YamlJsonSchemaTestSuite extends TestCase { suite.addTestSuite(YamlByJsonSchemaCompletionTest.class); suite.addTestSuite(YamlByJsonSchemaHeavyCompletionTest.class); suite.addTestSuite(YamlByJsonSchemaHighlightingTest.class); + suite.addTestSuite(YamlByJsonSchemaQuickFixTest.class); return suite; } }