Skip to content

Commit cc9d312

Browse files
authored
Merge pull request #88 from cedricziel/extension-key-discovery
Resolve extension-keys from unconventional paths
2 parents 39f49bd + 78f78a6 commit cc9d312

File tree

3 files changed

+232
-3
lines changed

3 files changed

+232
-3
lines changed

src/main/java/com/cedricziel/idea/typo3/index/ResourcePathIndex.java

Lines changed: 56 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.cedricziel.idea.typo3.index;
22

33
import com.intellij.openapi.project.Project;
4+
import com.intellij.openapi.vfs.VirtualFile;
45
import com.intellij.psi.PsiElement;
56
import com.intellij.psi.PsiManager;
67
import com.intellij.psi.search.GlobalSearchScope;
@@ -9,9 +10,12 @@
910
import com.intellij.util.io.KeyDescriptor;
1011
import gnu.trove.THashMap;
1112
import org.jetbrains.annotations.NotNull;
13+
import org.jetbrains.annotations.Nullable;
1214

1315
import java.util.*;
1416

17+
import static com.cedricziel.idea.typo3.util.ComposerUtil.findExtensionKey;
18+
1519
public class ResourcePathIndex extends ScalarIndexExtension<String> {
1620

1721
public static final ID<String, Void> KEY = ID.create("com.cedricziel.idea.typo3.index.resource_path");
@@ -57,12 +61,51 @@ public DataIndexer<String, Void, FileContent> getIndexer() {
5761
return inputData -> {
5862
Map<String, Void> map = new THashMap<>();
5963

60-
map.put(compileId(inputData), null);
64+
String path = inputData.getFile().getPath();
65+
if (path.contains("sysext") || path.contains("typo3conf/ext")) {
66+
map.put(compileId(inputData), null);
67+
68+
return map;
69+
}
70+
71+
VirtualFile extensionRootFolder = findExtensionRootFolder(inputData.getFile());
72+
if (extensionRootFolder != null) {
73+
// 1. try to read sibling composer.json
74+
VirtualFile composerJsonFile = extensionRootFolder.findChild("composer.json");
75+
if (composerJsonFile != null) {
76+
String extensionKey = findExtensionKey(composerJsonFile);
77+
if (extensionKey != null) {
78+
map.put(compileId(extensionRootFolder, extensionKey, inputData.getFile()), null);
79+
return map;
80+
}
81+
}
82+
83+
// 2. try to infer from directory name
84+
map.put(compileId(extensionRootFolder.getName(), extensionRootFolder.getPath(), inputData.getFile()), null);
85+
}
6186

6287
return map;
6388
};
6489
}
6590

91+
@Nullable
92+
private VirtualFile findExtensionRootFolder(@NotNull VirtualFile file) {
93+
if (file.isDirectory()) {
94+
VirtualFile child = file.findChild("ext_emconf.php");
95+
96+
if (child != null) {
97+
return file;
98+
}
99+
}
100+
101+
// dragons ahead.
102+
if (file.getParent() != null) {
103+
return findExtensionRootFolder(file.getParent());
104+
}
105+
106+
return null;
107+
}
108+
66109
private String compileId(FileContent inputData) {
67110
String path = inputData.getFile().getPath();
68111
String filePosition = "";
@@ -76,6 +119,16 @@ private String compileId(FileContent inputData) {
76119
return "EXT:" + filePosition;
77120
}
78121

122+
private String compileId(String extensionKey, String directoryPath, VirtualFile file) {
123+
124+
return "EXT:" + extensionKey + file.getPath().replace(directoryPath, "");
125+
}
126+
127+
private String compileId(VirtualFile extensionRootDirectory, String extensionKey, VirtualFile file) {
128+
129+
return "EXT:" + extensionKey + file.getPath().replace(extensionRootDirectory.getPath(), "");
130+
}
131+
79132
@NotNull
80133
@Override
81134
public KeyDescriptor<String> getKeyDescriptor() {
@@ -84,13 +137,13 @@ public KeyDescriptor<String> getKeyDescriptor() {
84137

85138
@Override
86139
public int getVersion() {
87-
return 0;
140+
return 1;
88141
}
89142

90143
@NotNull
91144
@Override
92145
public FileBasedIndex.InputFilter getInputFilter() {
93-
return file -> file.isInLocalFileSystem() && (file.getPath().contains("sysext") || file.getPath().contains("typo3conf/ext"));
146+
return VirtualFile::isInLocalFileSystem;
94147
}
95148

96149
@Override
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
package com.cedricziel.idea.typo3.util;
2+
3+
import com.google.gson.JsonElement;
4+
import com.google.gson.JsonObject;
5+
import com.google.gson.JsonSyntaxException;
6+
import com.intellij.openapi.vfs.VirtualFile;
7+
import com.jetbrains.php.composer.ComposerConfigUtils;
8+
import org.jetbrains.annotations.NotNull;
9+
import org.jetbrains.annotations.Nullable;
10+
11+
import java.io.IOException;
12+
13+
public class ComposerUtil {
14+
@Nullable
15+
public static String extensionKeyFromPackageName(JsonElement jsonElement) {
16+
JsonElement nameElement = jsonElement.getAsJsonObject().get("name");
17+
if (nameElement != null) {
18+
String name = nameElement.getAsString();
19+
if (name != null) {
20+
if (name.contains("/")) {
21+
return name.split("/")[1].replaceAll("-", "_");
22+
}
23+
}
24+
}
25+
26+
return null;
27+
}
28+
29+
public static String extensionKeyFromInstallerName(JsonElement jsonElement) {
30+
31+
JsonObject asJsonObject = jsonElement.getAsJsonObject();
32+
if (!asJsonObject.has("extra")) {
33+
return null;
34+
}
35+
36+
JsonObject extra = asJsonObject.get("extra").getAsJsonObject();
37+
if (!extra.has("installerName")) {
38+
return null;
39+
}
40+
41+
return extra.getAsJsonObject().getAsJsonPrimitive("installerName").getAsString();
42+
}
43+
44+
public static String extensionKeyFromExtraExtensionKey(JsonElement jsonElement) {
45+
46+
JsonObject asJsonObject = jsonElement.getAsJsonObject();
47+
if (!asJsonObject.has("extra")) {
48+
return null;
49+
}
50+
51+
JsonObject extra = asJsonObject.get("extra").getAsJsonObject();
52+
if (!extra.has("typo3/cms")) {
53+
return null;
54+
}
55+
56+
JsonObject typo3Extras = extra.getAsJsonObject("typo3/cms");
57+
if (!typo3Extras.has("extension-key")) {
58+
return null;
59+
}
60+
61+
return typo3Extras.getAsJsonPrimitive("extension-key").getAsString();
62+
}
63+
64+
public static String packageType(JsonElement jsonElement) {
65+
66+
JsonObject asJsonObject = jsonElement.getAsJsonObject();
67+
if (!asJsonObject.has("type")) {
68+
return null;
69+
}
70+
71+
return asJsonObject.get("type").getAsJsonPrimitive().getAsString();
72+
}
73+
74+
public static boolean isTYPO3ExtensionManifest(JsonElement jsonElement) {
75+
76+
String packageType = packageType(jsonElement);
77+
if (packageType == null) {
78+
return false;
79+
}
80+
81+
return packageType.equals("typo3-cms-extension");
82+
}
83+
84+
@Nullable
85+
public static String findExtensionKey(@NotNull VirtualFile composerJsonFile) {
86+
try {
87+
JsonElement jsonElement = ComposerConfigUtils.parseJson(composerJsonFile);
88+
89+
if (!isTYPO3ExtensionManifest(jsonElement)) {
90+
return null;
91+
}
92+
93+
// 1.1 find extra.typo3/cms.extension-key
94+
String extensionKeyFromExtrasTYPO3 = extensionKeyFromExtraExtensionKey(jsonElement);
95+
if (extensionKeyFromExtrasTYPO3 != null) {
96+
return extensionKeyFromExtrasTYPO3;
97+
}
98+
99+
// 1.2 find extra.installerName
100+
String extensionKeyFromInstallerName = extensionKeyFromInstallerName(jsonElement);
101+
if (extensionKeyFromInstallerName != null) {
102+
return extensionKeyFromInstallerName;
103+
}
104+
105+
// 1.3 last resort: package-name
106+
String extensionKeyFromPackageName = extensionKeyFromPackageName(jsonElement);
107+
if (extensionKeyFromPackageName != null) {
108+
return extensionKeyFromPackageName;
109+
}
110+
111+
112+
} catch (IOException e) {
113+
e.printStackTrace();
114+
} catch (JsonSyntaxException | IllegalStateException e) {
115+
// nothing, yo
116+
}
117+
118+
return null;
119+
}
120+
}

src/test/java/com/cedricziel/idea/typo3/index/ResourcePathIndexTest.java

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,60 @@ public void testResourcesAreIndexed() {
2222
assertContainsElements(lookupElementStrings, "EXT:foo/bar.php");
2323
assertContainsElements(lookupElementStrings, "EXT:baz/bar.png");
2424
}
25+
26+
public void testInstallerNameUnconventionalResourcePathsAreDetected() {
27+
28+
// extension key "cascaded" resolved through extra.typo3/cms.extension-key
29+
myFixture.addFileToProject("cc/ext_emconf.php", "");
30+
myFixture.addFileToProject("cc/composer.json", "{\n" +
31+
"\t\"name\": \"package/foo\",\n" +
32+
"\t\"bar\": \"baz\",\n" +
33+
"\t\"type\": \"typo3-cms-extension\",\n" +
34+
"\t\"extra\": {\n" +
35+
"\t\t\"installerName\": \"foo_bar_baz\",\n" +
36+
"\t\t\"typo3/cms\": {\n" +
37+
"\t\t\t\"extension-key\": \"cascaded\"\n" +
38+
"\t\t}\n" +
39+
"\t}\n" +
40+
"}\n");
41+
42+
// extension key "bar" resolved through package name
43+
myFixture.addFileToProject("bar_bz/ext_emconf.php", "");
44+
myFixture.addFileToProject("bar_bz/composer.json", "{\n" +
45+
"\t\"name\": \"package/bar\",\n" +
46+
"\t\"bar\": \"baz\",\n" +
47+
"\t\"type\": \"typo3-cms-extension\",\n" +
48+
"\t\"extra\": {\n" +
49+
"\t}\n" +
50+
"}\n");
51+
52+
// extension key "foo_bar_baz" resolved through the extras.installerName property
53+
myFixture.addFileToProject("foo/ext_emconf.php", "");
54+
myFixture.addFileToProject("foo/composer.json", "{\n" +
55+
"\t\"name\": \"package/foo\",\n" +
56+
"\t\"bar\": \"baz\",\n" +
57+
"\t\"type\": \"typo3-cms-extension\",\n" +
58+
"\t\"extra\": {\n" +
59+
"\t\t\"installerName\": \"foo_bar_baz\"\n" +
60+
"\t}\n" +
61+
"}\n");
62+
63+
// extension key "bingo" resolved through the folder
64+
myFixture.addFileToProject("bingo/ext_emconf.php", "");
65+
66+
myFixture.configureByText(PhpFileType.INSTANCE, "<?php \n" +
67+
"echo 'EXT:<caret>';");
68+
myFixture.completeBasic();
69+
70+
List<String> lookupElementStrings = myFixture.getLookupElementStrings();
71+
72+
if (lookupElementStrings == null) {
73+
fail("Could not complete");
74+
}
75+
76+
assertContainsElements(lookupElementStrings, "EXT:cascaded/ext_emconf.php");
77+
assertContainsElements(lookupElementStrings, "EXT:bingo/ext_emconf.php");
78+
assertContainsElements(lookupElementStrings, "EXT:foo_bar_baz/ext_emconf.php");
79+
assertContainsElements(lookupElementStrings, "EXT:bar/ext_emconf.php");
80+
}
2581
}

0 commit comments

Comments
 (0)