[json schema] AMPER-932 Don't suggest duplicate enum values if parent array assumes unique items

GitOrigin-RevId: a0e471c3d086ea2a4234501f75bbe4792b15a3d1
This commit is contained in:
Anton Lobov
2024-08-12 15:21:47 +02:00
committed by intellij-monorepo-bot
parent 45b39c3607
commit 1f409fad17
2 changed files with 23 additions and 2 deletions

View File

@@ -34,6 +34,7 @@ import com.intellij.psi.impl.source.tree.LeafPsiElement
import com.intellij.psi.injection.Injectable
import com.intellij.psi.util.PsiUtilCore
import com.intellij.psi.util.endOffset
import com.intellij.psi.util.parents
import com.intellij.ui.IconManager.Companion.getInstance
import com.intellij.ui.PlatformIcons
import com.intellij.util.ObjectUtils
@@ -209,11 +210,12 @@ class JsonSchemaCompletionContributor : CompletionContributor() {
val metadata = schema.enumMetadata
val isEnumOrderSensitive = schema.readChildNodeValue(X_INTELLIJ_ENUM_ORDER_SENSITIVE).toBoolean()
val anEnum = schema.enum
val filtered = filteredByDefault + getEnumItemsToSkip()
for (i in anEnum!!.indices) {
val o = anEnum[i]
if (insideStringLiteral && o !is String) continue
val variant = o.toString()
if (!filtered.contains(variant)) {
if (!filtered.contains(variant) && !filtered.contains(StringUtil.unquoteString(variant))) {
val valueMetadata = metadata?.get(StringUtil.unquoteString(variant))
val description = valueMetadata?.get("description")
val deprecated = valueMetadata?.get("deprecationMessage")
@@ -243,6 +245,19 @@ class JsonSchemaCompletionContributor : CompletionContributor() {
}
}
private fun getEnumItemsToSkip(): Set<String> {
// if the parent is an array, and it assumes unique items, we don't suggest the same enum items again
val position = psiWalker?.findPosition(psiWalker.findElementToCheck(completionPsiElement), false)
val containerSchema = position?.trimTail(1)?.let { JsonSchemaResolver(myProject, rootSchema, it, null) }?.resolve()?.singleOrNull()
return if (psiWalker != null && containerSchema?.isUniqueItems == true) {
val parentArray = completionPsiElement.parents(false).firstNotNullOfOrNull {
psiWalker.createValueAdapter(it)?.asArray
}
parentArray?.elements.orEmpty().map { StringUtil.unquoteString(it.delegate.text) }.toSet()
}
else emptySet()
}
fun suggestSpecialValues(type: JsonSchemaType?) {
if (!JsonSchemaVersion.isSchemaSchemaId(rootSchema.id) || type != JsonSchemaType._string) return
val propertyAdapter = psiWalker!!.getParentPropertyAdapter(originalPosition) ?: return
@@ -528,7 +543,7 @@ class JsonSchemaCompletionContributor : CompletionContributor() {
companion object {
// some schemas provide an empty array or an empty object in enum values...
private val filtered = setOf("[]", "{}", "[ ]", "{ }")
private val filteredByDefault = setOf("[]", "{}", "[ ]", "{ }")
private val commonAbbreviations = listOf("e.g.", "i.e.")
private fun findFirstSentence(sentence: String): String {

View File

@@ -28,6 +28,12 @@ class JsonBySchemaCompletionTest : JsonBySchemaCompletionBaseTest() {
"""{"prop": <caret>}""", "\"prima\"", "\"primus\"", "\"proto\"")
}
fun testEnumInArrayOfUniqueItems() {
// don't suggest the same enum elements again if the parent array assumes unique items
testImpl("""{"properties": {"prop": { "type": "array", "items": {"enum": ["prima", "proto", "primus"]}, "uniqueItems": true}}}""",
"""{"prop": ["prima", <caret>]}""", "\"primus\"", "\"proto\"")
}
fun testTopLevelAnyOfValues() {
testImpl("""{"properties": {"prop": {"anyOf": [{"enum": ["prima", "proto", "primus"]},""" + "{\"type\": \"boolean\"}]}}}",
"""{"prop": <caret>}""", "\"prima\"", "\"primus\"", "\"proto\"", "false", "true")