package fr.adrienbrault.idea.symfony2plugin.util; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import com.intellij.psi.xml.XmlFile; import com.intellij.psi.xml.XmlTag; import com.intellij.util.Consumer; import fr.adrienbrault.idea.symfony2plugin.dic.attribute.value.AttributeValueInterface; import fr.adrienbrault.idea.symfony2plugin.dic.attribute.value.DummyAttributeValue; import fr.adrienbrault.idea.symfony2plugin.dic.attribute.value.XmlTagAttributeValue; import fr.adrienbrault.idea.symfony2plugin.dic.attribute.value.YamlKeyValueAttributeValue; import fr.adrienbrault.idea.symfony2plugin.stubs.dict.FileResource; import fr.adrienbrault.idea.symfony2plugin.util.yaml.YamlHelper; import org.apache.commons.lang.StringUtils; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.yaml.psi.YAMLFile; import org.jetbrains.yaml.psi.YAMLKeyValue; /** * @author Daniel Espendiller <daniel@espendiller.net> */ public class FileResourceVisitorUtil { public static void visitFile(@NotNull PsiFile psiFile, @NotNull Consumer<FileResourceConsumer> consumer) { if(psiFile instanceof XmlFile) { visitXmlFile((XmlFile) psiFile, consumer); } else if(psiFile instanceof YAMLFile) { visitYamlFile((YAMLFile) psiFile, consumer); } } /** * foo: * resources: 'FOO' */ private static void visitYamlFile(@NotNull YAMLFile yamlFile, @NotNull Consumer<FileResourceConsumer> consumer) { for (YAMLKeyValue yamlKeyValue : YamlHelper.getTopLevelKeyValues(yamlFile)) { YAMLKeyValue resourceKey = YamlHelper.getYamlKeyValue(yamlKeyValue, "resource", true); if(resourceKey == null) { continue; } String resource = PsiElementUtils.trimQuote(resourceKey.getValueText()); if(StringUtils.isBlank(resource)) { continue; } consumer.consume(new FileResourceConsumer(resourceKey, yamlKeyValue, normalize(resource))); } } /** * <routes><import resource="FOO" /></routes> */ private static void visitXmlFile(@NotNull XmlFile psiFile, @NotNull Consumer<FileResourceConsumer> consumer) { XmlTag rootTag = psiFile.getRootTag(); if(rootTag == null || !"routes".equals(rootTag.getName())) { return; } for (XmlTag xmlTag : rootTag.findSubTags("import")) { String resource = xmlTag.getAttributeValue("resource"); if(StringUtils.isBlank(resource)) { continue; } consumer.consume(new FileResourceConsumer(xmlTag, xmlTag, normalize(resource))); } } @NotNull public static String normalize(@NotNull String resource) { return StringUtils.stripEnd(resource.replace("\\", "/").replaceAll("/+", "/"), "/"); } public static class FileResourceConsumer { @NotNull private final PsiElement psiElement; @Nullable private AttributeValueInterface attributeValue = null; @NotNull private final PsiElement scope; @NotNull private final String resource; public FileResourceConsumer(@NotNull PsiElement target, @NotNull PsiElement scope, @NotNull String resource) { this.psiElement = target; this.scope = scope; this.resource = resource; } @NotNull public AttributeValueInterface getAttributeValue() { if(this.attributeValue != null) { return this.attributeValue; } // We use lazy instances // @TODO: replace with factory pattern if(this.psiElement instanceof YAMLKeyValue) { return this.attributeValue = new YamlKeyValueAttributeValue((YAMLKeyValue) this.scope); } else if(this.psiElement instanceof XmlTag) { return this.attributeValue = new XmlTagAttributeValue((XmlTag) this.scope); } return this.attributeValue = new DummyAttributeValue(this.psiElement); } @NotNull public String getResource() { return resource; } @NotNull public PsiElement getPsiElement() { return psiElement; } @NotNull public FileResource createFileResource() { FileResource fileResource = new FileResource(this.getResource()); String prefix = this.getAttributeValue().getString("prefix"); if(prefix != null) { fileResource.setPrefix(prefix); } return fileResource; } } }