WEB-58267 WEB-58305 Support for NgOptimizedImage directive and inspection for converting from src to ngSrc

GitOrigin-RevId: c079af4ed192499ad97547eeccba9c0b8151ea90
This commit is contained in:
Piotr Tomiak
2023-02-20 16:50:06 +01:00
committed by intellij-monorepo-bot
parent 20302067a6
commit 9b118175ce
3 changed files with 45 additions and 17 deletions

View File

@@ -3,6 +3,7 @@ package com.intellij.htmltools.xml.util;
import com.intellij.codeInsight.lookup.AutoCompletionPolicy;
import com.intellij.codeInsight.lookup.LookupElement;
import com.intellij.codeInsight.lookup.LookupElementBuilder;
import com.intellij.html.impl.providers.HtmlAttributeValueProvider;
import com.intellij.html.impl.util.MicrodataUtil;
import com.intellij.lang.Language;
import com.intellij.openapi.fileTypes.FileType;
@@ -31,6 +32,7 @@ import com.intellij.util.ArrayUtil;
import com.intellij.util.ArrayUtilRt;
import com.intellij.util.ProcessingContext;
import com.intellij.util.containers.ContainerUtil;
import com.intellij.util.containers.JBIterable;
import com.intellij.util.io.URLUtil;
import com.intellij.xml.util.HtmlUtil;
import org.intellij.images.fileTypes.ImageFileTypeManager;
@@ -44,6 +46,8 @@ import org.jetbrains.annotations.Nullable;
import java.util.*;
import static com.intellij.util.ObjectUtils.doIfNotNull;
public class HtmlReferenceProvider extends PsiReferenceProvider {
@NonNls private static final String NAME_ATTR_LOCAL_NAME = "name";
@NonNls private static final String USEMAP_ATTR_NAME = "usemap";
@@ -52,7 +56,7 @@ public class HtmlReferenceProvider extends PsiReferenceProvider {
@NonNls private static final String SRC_ATTR_NAME = "src";
@NonNls private static final String JAVASCRIPT_PREFIX = "javascript:";
private static final FileType[] IMAGE_FILE_TYPES = new FileType[]{ImageFileTypeManager.getInstance().getImageFileType()};
public static final FileType[] IMAGE_FILE_TYPES = new FileType[]{ImageFileTypeManager.getInstance().getImageFileType()};
public static final String LABELLEDBY = "aria-labelledby";
public static ElementFilter getFilter() {
@@ -284,7 +288,6 @@ public class HtmlReferenceProvider extends PsiReferenceProvider {
return fileType == null ? null : new FileType[]{fileType};
}
@SuppressWarnings({"HardCodedStringLiteral"})
public static String[] getAttributeValues() {
return new String[] {SRC_ATTR_NAME, HREF_ATTRIBUTE_NAME, USEMAP_ATTR_NAME, "action", "background", "width", "height", "type", "bgcolor", "color", "vlink",
"link", "alink", "text", "name", HtmlUtil.ID_ATTRIBUTE_NAME, HtmlUtil.CLASS_ATTRIBUTE_NAME, FOR_ATTR_NAME, MicrodataUtil.ITEM_REF, "data", "poster", "srcset",
@@ -388,9 +391,15 @@ public class HtmlReferenceProvider extends PsiReferenceProvider {
@Nullable
public static ImageInfoReader.Info getImageInfo(@NotNull final XmlTag tag) {
return CachedValuesManager.getCachedValue(tag, () -> {
final XmlAttribute src = tag.getAttribute(SRC_ATTR_NAME, null);
if (src != null) {
final PsiFile psiFile = FileReferenceUtil.findFile(src.getValueElement());
PsiElement srcValue = JBIterable.from(HtmlAttributeValueProvider.EP_NAME.getExtensionList())
.filterMap(it -> it.getCustomAttributeValue(tag, SRC_ATTR_NAME))
.first();
if (srcValue == null) {
var attr = tag.getAttribute(SRC_ATTR_NAME, null);
srcValue = attr != null ? attr.getValueElement() : null;
}
if (srcValue != null) {
final PsiFile psiFile = FileReferenceUtil.findFile(srcValue);
if (psiFile != null) {
final VirtualFile virtualFile = psiFile.getVirtualFile();
if (virtualFile instanceof VirtualFileWithId) {
@@ -398,19 +407,19 @@ public class HtmlReferenceProvider extends PsiReferenceProvider {
if (value == null) return null;
return CachedValueProvider.Result.create(
new ImageInfoReader.Info(value.width, value.height, value.bpp, IfsUtil.isSVG(virtualFile)),
src,
srcValue,
virtualFile
);
}
}
final String srcValue = src.getValue();
if (srcValue != null && URLUtil.isDataUri(srcValue)) {
final byte[] bytesFromDataUri = URLUtil.getBytesFromDataUri(srcValue);
final String srcValueText = doIfNotNull(srcValue.getText(), StringUtil::unquoteString);
if (srcValueText != null && URLUtil.isDataUri(srcValueText)) {
final byte[] bytesFromDataUri = URLUtil.getBytesFromDataUri(srcValueText);
if (bytesFromDataUri != null) {
try {
ImageInfoReader.Info info = ImageInfoReader.getInfo(bytesFromDataUri);
if (info != null) {
return CachedValueProvider.Result.create(info, src);
return CachedValueProvider.Result.create(info, srcValue);
}
}
catch (Exception ignored) {

View File

@@ -18,6 +18,7 @@ package com.intellij.codeInspection.htmlInspections;
import com.intellij.codeInsight.daemon.impl.analysis.XmlHighlightingAwareElementDescriptor;
import com.intellij.codeInspection.*;
import com.intellij.codeInspection.util.InspectionMessage;
import com.intellij.html.impl.providers.HtmlAttributeValueProvider;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.NlsSafe;
@@ -26,6 +27,7 @@ import com.intellij.psi.html.HtmlTag;
import com.intellij.psi.xml.XmlAttribute;
import com.intellij.psi.xml.XmlTag;
import com.intellij.psi.xml.XmlToken;
import com.intellij.util.containers.JBIterable;
import com.intellij.xml.XmlAttributeDescriptor;
import com.intellij.xml.XmlElementDescriptor;
import com.intellij.xml.XmlExtension;
@@ -113,8 +115,10 @@ public class RequiredAttributesInspectionBase extends HtmlLocalInspectionTool im
if (!hasAttribute(tag, attrName) &&
!XmlExtension.getExtension(tag.getContainingFile()).isRequiredAttributeImplicitlyPresent(tag, attrName)) {
LocalQuickFix insertRequiredAttributeIntention = isOnTheFly ? XmlQuickFixFactory.getInstance().insertRequiredAttributeFix(tag, attrName) : null;
final String localizedMessage = XmlAnalysisBundle.message("xml.inspections.element.doesnt.have.required.attribute", name, attrName);
LocalQuickFix insertRequiredAttributeIntention =
isOnTheFly ? XmlQuickFixFactory.getInstance().insertRequiredAttributeFix(tag, attrName) : null;
final String localizedMessage =
XmlAnalysisBundle.message("xml.inspections.element.doesnt.have.required.attribute", name, attrName);
reportOneTagProblem(
tag,
attrName,
@@ -130,6 +134,10 @@ public class RequiredAttributesInspectionBase extends HtmlLocalInspectionTool im
}
private static boolean hasAttribute(XmlTag tag, String attrName) {
if (JBIterable.from(HtmlAttributeValueProvider.EP_NAME.getExtensionList())
.filterMap(it -> it.getCustomAttributeValue(tag, attrName)).first() != null) {
return true;
}
final XmlAttribute attribute = tag.getAttribute(attrName);
if (attribute == null) return false;
if (attribute.getValueElement() != null) return true;
@@ -149,17 +157,17 @@ public class RequiredAttributesInspectionBase extends HtmlLocalInspectionTool im
if (tag instanceof HtmlTag) {
htmlTag = true;
if(isAdditionallyDeclared(getAdditionalEntries(), name)) return;
if (isAdditionallyDeclared(getAdditionalEntries(), name)) return;
}
LocalQuickFix[] fixes;
ProblemHighlightType highlightType;
if (htmlTag) {
fixes = basicIntention == null ? new LocalQuickFix[] {addAttributeFix} : new LocalQuickFix[]{addAttributeFix, basicIntention};
fixes = basicIntention == null ? new LocalQuickFix[]{addAttributeFix} : new LocalQuickFix[]{addAttributeFix, basicIntention};
highlightType = isInjectedWithoutValidation(tag) ? ProblemHighlightType.INFORMATION : ProblemHighlightType.GENERIC_ERROR_OR_WARNING;
}
else {
fixes = basicIntention == null ? LocalQuickFix.EMPTY_ARRAY : new LocalQuickFix[] {basicIntention};
fixes = basicIntention == null ? LocalQuickFix.EMPTY_ARRAY : new LocalQuickFix[]{basicIntention};
highlightType = ProblemHighlightType.ERROR;
}
if (isOnTheFly || highlightType != ProblemHighlightType.INFORMATION) {

View File

@@ -16,7 +16,9 @@
package com.intellij.html.impl.providers;
import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.psi.PsiElement;
import com.intellij.psi.xml.XmlTag;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class HtmlAttributeValueProvider {
@@ -27,9 +29,18 @@ public class HtmlAttributeValueProvider {
* Calculates attribute value. Used when it is impossible to get attribute value as text of PSI element
* @return calculated value
*/
@Nullable
public String getCustomAttributeValues(final XmlTag tag, final String attributeName) {
public @Nullable String getCustomAttributeValues(@NotNull XmlTag tag, @NotNull String attributeName) {
return null;
}
/**
* Allows to provide an attribute value from a different non-standard attribute to work with in place of a regular one.
* It is useful in frameworks, e.g. to provide a directive attribute value instead of {@code src} attribute of {@code <img>} tag.
* @return a custom attribute to use instead of a standard one
*/
public @Nullable PsiElement getCustomAttributeValue(@NotNull XmlTag tag, @NotNull String attributeName) {
return null;
}
}