package com.cedricziel.idea.typo3.domain.factory;
import com.cedricziel.idea.typo3.domain.TYPO3ExtensionDefinition;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.newvfs.impl.VirtualDirectoryImpl;
import com.intellij.openapi.vfs.newvfs.impl.VirtualFileSystemEntry;
import com.jetbrains.php.composer.ComposerConfigUtils;
import org.apache.commons.lang.StringUtils;
import java.io.IOException;
import static com.cedricziel.idea.typo3.domain.TYPO3ExtensionDefinition.COMPOSER_TYPE_CMS_EXTENSION;
import static com.cedricziel.idea.typo3.domain.TYPO3ExtensionDefinition.COMPOSER_TYPE_CMS_FRAMEWORK;
public class ExtensionDefinitionFactory {
public static TYPO3ExtensionDefinition fromDirectory(VirtualDirectoryImpl virtualDirectory) {
TYPO3ExtensionDefinition extensionDefinition = null;
// try finding composer manifest
VirtualFileSystemEntry composerManifest = virtualDirectory.findChild("composer.json");
if (composerManifest != null) {
try {
extensionDefinition = fromComposerManifest(composerManifest);
} catch (IOException e) {
e.printStackTrace();
}
}
return extensionDefinition != null ? extensionDefinition : null;
}
/**
* Reads a composer manifest and compiles it into a {@link TYPO3ExtensionDefinition}, if possible.
*
* @param composerManifest The manifest virtual file system entry to parse
* @return The derived extension definition.
* @throws IOException thrown if reading the manifest fails.
*/
private static TYPO3ExtensionDefinition fromComposerManifest(VirtualFile composerManifest) throws IOException {
TYPO3ExtensionDefinition extensionDefinition = new TYPO3ExtensionDefinition();
extensionDefinition.setRootDirectory(composerManifest.getParent());
JsonElement jsonElement = ComposerConfigUtils.parseJson(composerManifest);
if (jsonElement.isJsonObject()) {
JsonObject jsonObject = jsonElement.getAsJsonObject();
String packageName = "";
String composerPackageType = "";
String extensionKey = "";
JsonElement nameElement = jsonObject.get("name");
if (nameElement == null) {
return null;
}
packageName = nameElement.getAsString();
JsonElement typeElement = jsonObject.get("type");
if (typeElement.isJsonPrimitive()) {
composerPackageType = typeElement.getAsString();
if (!isValidPackageType(composerPackageType)) {
return null;
}
}
extensionDefinition.setPackageName(packageName);
/*
Here we either extract the extension key from the composer manifest or
guess the extension key from the package name.
*/
if (jsonObject.has("extra") && !extractExtensionKeyFromComposerExtras(jsonObject.getAsJsonObject()).isEmpty()) {
extensionKey = extractExtensionKeyFromComposerExtras(jsonObject.getAsJsonObject());
} else {
extensionKey = extensionKeyFromPackageName(packageName);
if (composerPackageType.equals(COMPOSER_TYPE_CMS_FRAMEWORK)) {
if ("cms_".equals(extensionKey.substring(0, 4))) {
extensionKey = extensionKey.substring(4);
}
}
}
extensionDefinition.setExtensionKey(extensionKey);
}
return extensionDefinition;
}
/**
* Tries to extract the extensionKey from composer extras. Expects the following data structur:
* <p>
* <pre>
* "extra": {
* "installer-name": "formengine_map",
* "typo3/cms": {
* "extensionKey": "formengine_map"
* }
* }
* </pre>
*
* @param composerExtrasObject A json object with the structure of composer extras
* @return The extension key if properly extracted or an empty string
*/
private static String extractExtensionKeyFromComposerExtras(JsonObject composerExtrasObject) {
if (composerExtrasObject.has("installer-name") && !composerExtrasObject.get("installer-name").getAsString().isEmpty()) {
return composerExtrasObject.get("installer-name").getAsString();
}
if (composerExtrasObject.has("typo3/cms") && composerExtrasObject.get("typo3/cms").isJsonObject()) {
JsonObject typo3cmsElement = composerExtrasObject.get("typo3/cms").getAsJsonObject();
if (typo3cmsElement.has("extensionKey") && !typo3cmsElement.get("extensionKey").getAsString().isEmpty()) {
return typo3cmsElement.get("extensionKey").getAsString();
}
}
return "";
}
/**
* TYPO3 CMS Extensions should only ever have either type "typo3-cms-framework" or "typo3-cms-extension".
*
* @param composerPackageType The package type to test
* @return Whether the package key is valid.
*/
private static boolean isValidPackageType(String composerPackageType) {
return !composerPackageType.isEmpty()
&& (composerPackageType.equals(COMPOSER_TYPE_CMS_EXTENSION) || composerPackageType.equals(COMPOSER_TYPE_CMS_FRAMEWORK));
}
/**
* Guesses an extension key from the composer package name.
*
* @param packageName The package name to analyze
* @return
*/
private static String extensionKeyFromPackageName(String packageName) {
String[] split = StringUtils.split(packageName, "/");
if (split.length < 2) {
return packageName;
}
return StringUtils
.lowerCase(split[1])
.replace("-", "_");
}
}