Skip to content

Commit

Permalink
refactor ComponentUsageIndex
Browse files Browse the repository at this point in the history
  • Loading branch information
Haehnchen committed Feb 26, 2024
1 parent 3b58b4b commit ff6cc5b
Show file tree
Hide file tree
Showing 2 changed files with 121 additions and 87 deletions.
90 changes: 3 additions & 87 deletions src/main/java/de/espend/idea/vuejs/index/ComponentUsageIndex.java
Original file line number Diff line number Diff line change
@@ -1,31 +1,14 @@
package de.espend.idea.vuejs.index;

import com.intellij.lang.ecmascript6.psi.ES6ImportedBinding;
import com.intellij.lang.ecmascript6.psi.ES6Property;
import com.intellij.lang.ecmascript6.resolve.JSFileReferencesUtil;
import com.intellij.lang.javascript.psi.JSExpression;
import com.intellij.lang.javascript.psi.JSObjectLiteralExpression;
import com.intellij.lang.javascript.psi.JSProperty;
import com.intellij.lang.javascript.psi.JSReferenceExpression;
import com.intellij.lang.javascript.psi.impl.JSReferenceExpressionImpl;
import com.intellij.lang.javascript.psi.util.JSStubBasedPsiTreeUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiRecursiveElementVisitor;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.xml.XmlTag;
import com.intellij.util.PathUtil;
import com.intellij.util.indexing.*;
import com.intellij.util.io.DataExternalizer;
import com.intellij.util.io.EnumeratorStringDescriptor;
import com.intellij.util.io.KeyDescriptor;
import de.espend.idea.vuejs.index.externalizer.StringListDataExternalizer;
import de.espend.idea.vuejs.utils.VueJsUtil;
import de.espend.idea.vuejs.index.utils.VueJsComponentIndexUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.vuejs.index.VueFrameworkHandlerKt;
import org.jetbrains.vuejs.lang.html.VueFile;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
Expand All @@ -50,75 +33,8 @@ public class ComponentUsageIndex extends FileBasedIndexExtension<String, List<St
Map<String, List<String>> imports = new HashMap<>();

if (fileContent.getPsiFile() instanceof VueFile vueFile) {
for (XmlTag script : VueFrameworkHandlerKt.findTopLevelVueTags(vueFile, "script")) {
script.acceptChildren(new PsiRecursiveElementVisitor() {
@Override
public void visitElement(@NotNull PsiElement element) {
if (element instanceof ES6ImportedBinding es6ImportedBinding) {
visitImportedBinding(es6ImportedBinding);
} else if (element instanceof JSProperty jsProperty && "components".equals(jsProperty.getName())) {
// components: {Foobar}
JSExpression value = jsProperty.getValue();
if (value instanceof JSObjectLiteralExpression jsObjectLiteralExpression) {
for (ES6Property es6Property : PsiTreeUtil.collectElementsOfType(jsObjectLiteralExpression, ES6Property.class)) {
JSExpression value1 = es6Property.getValue();
if (value1 instanceof JSReferenceExpression jsReferenceExpression) {
String referenceName = JSReferenceExpressionImpl.getReferenceName(jsReferenceExpression.getNode());
if (referenceName != null) {
for (PsiElement resolveLocallyWithMergedResult : JSStubBasedPsiTreeUtil.resolveLocallyWithMergedResults(referenceName, jsReferenceExpression)) {
if (resolveLocallyWithMergedResult instanceof ES6ImportedBinding es6ImportedBinding) {
visitImportedBinding(es6ImportedBinding);
}
}
}
}
}
}
}
super.visitElement(element);
}

private void visitImportedBinding(@NotNull ES6ImportedBinding es6ImportedBinding) {
VueJsUtil.ES6Import singleImported = VueJsUtil.getSingleImported(es6ImportedBinding);
if (singleImported != null) {
String fileName = PathUtil.getFileName(singleImported.fileNameWithoutExtension());
imports.put(JSFileReferencesUtil.getFileNameWithoutExtension(fileName, new String[] {".vue"}), Arrays.asList(singleImported.referenceText(), singleImported.importName()));
}
}
});
}

Map<String, String> directoryScope = new HashMap<>();
VirtualFile[] vueFiles = Arrays.stream(fileContent.getPsiFile()
.getVirtualFile()
.getParent()
.getChildren())
.filter(v -> "vue".equalsIgnoreCase(v.getExtension()) && !v.getName().equalsIgnoreCase(fileContent.getFileName()))
.toArray(VirtualFile[]::new);

if (vueFiles.length > 0) {
for (VirtualFile child : vueFiles) {
if ("vue".equalsIgnoreCase(child.getExtension())) {
String substring = child.getName().substring(0, child.getName().length() - 4);

directoryScope.put(VueJsUtil.convertKebabCaseToCamelCase(substring), child.getName());
directoryScope.put(VueJsUtil.convertToKebabCase(substring), child.getName());
}
}

for (XmlTag script : VueFrameworkHandlerKt.findTopLevelVueTags(vueFile, "template")) {
script.acceptChildren(new PsiRecursiveElementVisitor() {
@Override
public void visitElement(@NotNull PsiElement element) {
if (element instanceof XmlTag xmlTag && directoryScope.containsKey(xmlTag.getName())) {
imports.put(VueJsUtil.convertKebabCaseToCamelCase(((XmlTag) element).getName()), Arrays.asList("./" + directoryScope.get(xmlTag.getName()), ((XmlTag) element).getName()));
}

super.visitElement(element);
}
});
}
}
imports.putAll(VueJsComponentIndexUtil.getComponentsForIndex(vueFile));
imports.putAll(VueJsComponentIndexUtil.getSameDirectoryComponentsForIndex(vueFile));
}

return imports;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
package de.espend.idea.vuejs.index.utils;

import com.intellij.lang.ecmascript6.psi.ES6ImportedBinding;
import com.intellij.lang.ecmascript6.psi.ES6Property;
import com.intellij.lang.ecmascript6.resolve.JSFileReferencesUtil;
import com.intellij.lang.javascript.psi.JSExpression;
import com.intellij.lang.javascript.psi.JSObjectLiteralExpression;
import com.intellij.lang.javascript.psi.JSProperty;
import com.intellij.lang.javascript.psi.JSReferenceExpression;
import com.intellij.lang.javascript.psi.impl.JSReferenceExpressionImpl;
import com.intellij.lang.javascript.psi.util.JSStubBasedPsiTreeUtil;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiRecursiveElementVisitor;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.psi.xml.XmlFile;
import com.intellij.psi.xml.XmlTag;
import com.intellij.util.PathUtil;
import de.espend.idea.vuejs.utils.VueJsUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.vuejs.index.VueFrameworkHandlerKt;
import org.jetbrains.vuejs.lang.html.VueFile;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
* @author Daniel Espendiller <[email protected]>
*/
public class VueJsComponentIndexUtil {
@NotNull
public static Map<String, List<String>> getComponentsForIndex(@NotNull XmlFile vueFile) {
Map<String, List<String>> imports = new HashMap<>();

List<XmlTag> script1 = VueFrameworkHandlerKt.findTopLevelVueTags(vueFile, "script");
for (XmlTag script : script1) {
script.acceptChildren(new PsiRecursiveElementVisitor() {
@Override
public void visitElement(@NotNull PsiElement element) {
if (element instanceof ES6ImportedBinding es6ImportedBinding) {
visitImportedBinding(es6ImportedBinding);
} else if (element instanceof JSProperty jsProperty && "components".equals(jsProperty.getName())) {
// components: {Foobar}
JSExpression value = jsProperty.getValue();
if (value instanceof JSObjectLiteralExpression jsObjectLiteralExpression) {
for (ES6Property es6Property : PsiTreeUtil.collectElementsOfType(jsObjectLiteralExpression, ES6Property.class)) {
JSExpression value1 = es6Property.getValue();
if (value1 instanceof JSReferenceExpression jsReferenceExpression) {
String referenceName = JSReferenceExpressionImpl.getReferenceName(jsReferenceExpression.getNode());
if (referenceName != null) {
for (PsiElement resolveLocallyWithMergedResult : JSStubBasedPsiTreeUtil.resolveLocallyWithMergedResults(referenceName, jsReferenceExpression)) {
if (resolveLocallyWithMergedResult instanceof ES6ImportedBinding es6ImportedBinding) {
visitImportedBinding(es6ImportedBinding);
}
}
}
}
}
}
}
super.visitElement(element);
}

private void visitImportedBinding(@NotNull ES6ImportedBinding es6ImportedBinding) {
VueJsUtil.ES6Import singleImported = VueJsUtil.getSingleImported(es6ImportedBinding);
if (singleImported != null) {
String fileName = PathUtil.getFileName(singleImported.fileNameWithoutExtension());
imports.put(JSFileReferencesUtil.getFileNameWithoutExtension(fileName, new String[] {".vue"}), Arrays.asList(singleImported.referenceText(), singleImported.importName()));
}
}
});
}

return imports;
}

@NotNull
public static Map<String, List<String>> getSameDirectoryComponentsForIndex(@NotNull VueFile vueFile) {
Map<String, List<String>> imports = new HashMap<>();

Map<String, String> directoryScope = new HashMap<>();

VirtualFile[] vueFiles = Arrays.stream(vueFile
.getVirtualFile()
.getParent()
.getChildren())
.filter(v -> "vue".equalsIgnoreCase(v.getExtension()) && !v.getName().equalsIgnoreCase(vueFile.getName()))
.toArray(VirtualFile[]::new);

if (vueFiles.length > 0) {
for (VirtualFile child : vueFiles) {
if ("vue".equalsIgnoreCase(child.getExtension())) {
String substring = child.getName().substring(0, child.getName().length() - 4);

directoryScope.put(VueJsUtil.convertKebabCaseToCamelCase(substring), child.getName());
directoryScope.put(VueJsUtil.convertToKebabCase(substring), child.getName());
}
}

for (XmlTag script : VueFrameworkHandlerKt.findTopLevelVueTags(vueFile, "template")) {
script.acceptChildren(new PsiRecursiveElementVisitor() {
@Override
public void visitElement(@NotNull PsiElement element) {
if (element instanceof XmlTag xmlTag && directoryScope.containsKey(xmlTag.getName())) {
imports.put(VueJsUtil.convertKebabCaseToCamelCase(((XmlTag) element).getName()), Arrays.asList("./" + directoryScope.get(xmlTag.getName()), ((XmlTag) element).getName()));
}

super.visitElement(element);
}
});
}
}

return imports;
}
}

0 comments on commit ff6cc5b

Please sign in to comment.