diff --git a/json/resources/intellij.json.xml b/json/resources/intellij.json.xml index c387e6e3146a..fc029387a222 100644 --- a/json/resources/intellij.json.xml +++ b/json/resources/intellij.json.xml @@ -137,6 +137,8 @@ + + diff --git a/json/src/com/intellij/json/JsonWebReferenceContributor.java b/json/src/com/intellij/json/JsonWebReferenceContributor.java new file mode 100644 index 000000000000..3776bd31d122 --- /dev/null +++ b/json/src/com/intellij/json/JsonWebReferenceContributor.java @@ -0,0 +1,56 @@ +// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package com.intellij.json; + +import com.intellij.json.psi.JsonProperty; +import com.intellij.json.psi.JsonStringLiteral; +import com.intellij.json.psi.JsonValue; +import com.intellij.openapi.paths.GlobalPathReferenceProvider; +import com.intellij.openapi.paths.WebReference; +import com.intellij.openapi.util.TextRange; +import com.intellij.psi.*; +import com.intellij.util.ProcessingContext; +import org.jetbrains.annotations.NotNull; + +import static com.intellij.patterns.PlatformPatterns.psiElement; + +final class JsonWebReferenceContributor extends PsiReferenceContributor { + @Override + public void registerReferenceProviders(@NotNull PsiReferenceRegistrar registrar) { + registrar.registerReferenceProvider( + psiElement(JsonStringLiteral.class), + new PsiReferenceProvider() { + @Override + public boolean acceptsTarget(@NotNull PsiElement target) { + return false; // web references do not point to any real PsiElement + } + + @Override + public PsiReference @NotNull [] getReferencesByElement(@NotNull PsiElement element, @NotNull ProcessingContext context) { + if (!(element instanceof JsonStringLiteral)) return PsiReference.EMPTY_ARRAY; + JsonStringLiteral stringLiteral = (JsonStringLiteral)element; + + PsiElement parent = stringLiteral.getParent(); + if (!(parent instanceof JsonProperty)) return PsiReference.EMPTY_ARRAY; + + JsonValue jsonValueElement = ((JsonProperty)parent).getValue(); + if (element != jsonValueElement) return PsiReference.EMPTY_ARRAY; + + if (element.getTextLength() > 1000) return PsiReference.EMPTY_ARRAY; // JSON may be used as data format for huge strings + if (!element.textContains(':')) return PsiReference.EMPTY_ARRAY; + + String textValue = stringLiteral.getValue(); + + if (GlobalPathReferenceProvider.isWebReferenceUrl(textValue)) { + TextRange valueTextRange = ElementManipulators.getValueTextRange(stringLiteral); + if (valueTextRange.isEmpty()) return PsiReference.EMPTY_ARRAY; + + return new PsiReference[]{new WebReference(element, valueTextRange, textValue)}; + } + + return PsiReference.EMPTY_ARRAY; + } + }, + PsiReferenceRegistrar.LOWER_PRIORITY + ); + } +} diff --git a/json/tests/test/com/intellij/json/JsonHighlightingTest.java b/json/tests/test/com/intellij/json/JsonHighlightingTest.java index 39f31fdd9834..2e6d0f2e886b 100644 --- a/json/tests/test/com/intellij/json/JsonHighlightingTest.java +++ b/json/tests/test/com/intellij/json/JsonHighlightingTest.java @@ -87,6 +87,10 @@ public class JsonHighlightingTest extends JsonHighlightingTestBase { doTest(); } + public void testWebUrls() { + doTest(); + } + public void testRainbow() { myFixture.testRainbow("test.json", "{\n" + diff --git a/json/tests/testData/highlighting/WebUrls.json b/json/tests/testData/highlighting/WebUrls.json new file mode 100644 index 000000000000..90c3a487a08e --- /dev/null +++ b/json/tests/testData/highlighting/WebUrls.json @@ -0,0 +1,6 @@ +{ + "some": "http://localhost", + "secure": "https://localhost", + "not-url": "https :// localhost", + "https://key-not-checked": "value" +} \ No newline at end of file