package com.chrisfolger.needsmoredojo.core.amd.filesystem; import com.chrisfolger.needsmoredojo.core.amd.importing.ImportResolver; import com.chrisfolger.needsmoredojo.core.amd.naming.NameResolver; import com.intellij.lang.javascript.psi.JSArrayLiteralExpression; import com.intellij.lang.javascript.psi.JSCallExpression; import com.intellij.lang.javascript.psi.JSExpression; import com.intellij.lang.javascript.psi.JSRecursiveElementVisitor; import com.intellij.openapi.project.Project; import com.intellij.openapi.vfs.VfsUtilCore; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; import com.intellij.psi.search.FilenameIndex; import com.intellij.psi.search.GlobalSearchScope; import com.intellij.psi.xml.XmlAttribute; import com.intellij.psi.xml.XmlTag; import java.util.*; public class DojoModuleFileResolver { public static boolean isDojoModule(String path) { return path.startsWith("dojo") || path.startsWith("dijit") || path.startsWith("dgrid") || path.startsWith("dojox"); } public static boolean isInDojoSources(String directory) { return directory.contains("/xstyle/") || directory.contains("/nls/") || directory.contains("/dojo/") || directory.contains("/dijit/") || directory.contains("/dojox/") || directory.contains("/dgrid/") || directory.contains("/util/buildscripts/"); } /** * gets a list of all files that are part of your dojo project sources. * only retrieves javascript files * * @param project * @return */ public Collection<VirtualFile> getAllDojoProjectSourceFiles(Project project) { VirtualFile[] sourceDirectories = SourcesLocator.getProjectSourceDirectories(project, true); List<VirtualFile> files = new ArrayList<VirtualFile>(); for(VirtualFile file : sourceDirectories) { files.add(file); } Set<VirtualFile> psiFiles = new HashSet<VirtualFile>(); Collection<VirtualFile> results = FilenameIndex.getAllFilesByExt(project, "js", GlobalSearchScope.projectScope(project)); for(VirtualFile result : results) { for(VirtualFile directory : sourceDirectories) { if(VfsUtilCore.isAncestor(directory, result, false)) { psiFiles.add(result); continue; } } } return results; } public Set<String> getDojoModulesInJavaScriptFiles(Project project) { Collection<VirtualFile> files = FilenameIndex.getAllFilesByExt(project, "js"); Set<PsiFile> potentialFiles = new HashSet<PsiFile>(); for(VirtualFile file : files) { if(isInDojoSources(file.getCanonicalPath())) continue; PsiFile psiFile = PsiManager.getInstance(project).findFile(file); potentialFiles.add(psiFile); } Set<String> matches = new HashSet<String>(); HashSet<PsiDirectory> attemptedDirectories = new HashSet<PsiDirectory>(); for(PsiFile file : potentialFiles) { if(attemptedDirectories.contains(file.getParent())) continue; attemptedDirectories.add(file.getParent()); if(file.getText().contains("define(")) { String path = file.getVirtualFile().getCanonicalPath(); path = path.substring(path.lastIndexOf('/') + 1); path = path.substring(0, path.length() - 3); matches.add(path); } } return matches; } public Set<String> getDojoModulesInHtmlFile(PsiFile file) { final Set<String> modules = new HashSet<String>(); file.acceptChildren(new JSRecursiveElementVisitor() { @Override public void visitJSCallExpression(JSCallExpression node) { if(!node.getText().startsWith("require")) { super.visitJSCallExpression(node); return; } if(node.getArguments().length > 0 && node.getArguments()[0] instanceof JSArrayLiteralExpression) { JSArrayLiteralExpression arguments = (JSArrayLiteralExpression) node.getArguments()[0]; for(JSExpression literal : arguments.getExpressions()) { String literalText = literal.getText().replaceAll("'", "").replaceAll("\"", ""); if(!isDojoModule(literalText)) { modules.add(literalText); } } } super.visitJSCallExpression(node); } }); file.acceptChildren(new XmlRecursiveElementVisitor() { @Override public void visitXmlTag(XmlTag tag) { super.visitXmlTag(tag); } @Override public void visitXmlAttribute(XmlAttribute attribute) { if(attribute.getName().equals("data-dojo-type")) { if(!isDojoModule(attribute.getValue())) { modules.add(attribute.getValue()); } } super.visitXmlAttribute(attribute); } }); return modules; } public PsiFile resolveReferencedFile(Project project, PsiFile fileContainingDefine, String defineText) { ImportResolver resolver = new ImportResolver(); String text = defineText.replaceAll("'|\"", ""); PsiFile[] possibleFiles = resolver.getPossibleDojoImportFiles(project, NameResolver.getModuleName(text), false, false); LinkedHashMap<String, PsiFile> possibleImportedFiles = resolver.getChoicesFromFiles(possibleFiles, new SourcesLocator().getSourceLibraries(project).toArray(new SourceLibrary[0]), NameResolver.getModuleName(text), fileContainingDefine, false, true); for(String importString : possibleImportedFiles.keySet()) { if(importString.equals(text)) { return possibleImportedFiles.get(importString); } } return null; } public PsiFile resolveReferencedFile(Project project, PsiElement define) { return resolveReferencedFile(project, define.getContainingFile(), define.getText()); } public Set<String> getDirectoriesForDojoModules(Project project, Set<String> modules) { Set<String> possibleDirectories = new HashSet<String>(); for(String module : modules) { String moduleParent = module; if(module.contains("/")) { module = module.substring(module.lastIndexOf("/") + 1); } PsiFile[] files = FilenameIndex.getFilesByName(project, module + ".js", GlobalSearchScope.projectScope(project)); for(PsiFile file : files) { if( file.getVirtualFile().getCanonicalPath().contains(moduleParent)) { possibleDirectories.add(file.getParent().getParent().getName() + " (" + file.getParent().getParent().getVirtualFile().getCanonicalPath() + ")"); } } } return possibleDirectories; } }