src/com/intellij/idea/plugin/hybris/impex/psi/ImpexPsiUtil.kt (183 lines of code) (raw):
/*
* This file is part of "SAP Commerce Developers Toolset" plugin for IntelliJ IDEA.
* Copyright (C) 2019-2024 EPAM Systems <hybrisideaplugin@epam.com> and contributors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
@file:JvmName("ImpexPsiUtil")
package com.intellij.idea.plugin.hybris.impex.psi
import com.intellij.idea.plugin.hybris.common.HybrisConstants
import com.intellij.idea.plugin.hybris.impex.constants.modifier.AttributeModifier
import com.intellij.idea.plugin.hybris.properties.PropertyService
import com.intellij.idea.plugin.hybris.system.type.psi.reference.result.*
import com.intellij.openapi.project.DumbService
import com.intellij.openapi.util.TextRange
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiPolyVariantReference
import com.intellij.psi.util.*
fun getHeaderLine(element: ImpexFullHeaderParameter): ImpexHeaderLine? = PsiTreeUtil
.getParentOfType(element, ImpexHeaderLine::class.java)
fun getValueGroup(element: ImpexString): ImpexValueGroup? = PsiTreeUtil
.getParentOfType(element, ImpexValueGroup::class.java)
fun getValueGroup(element: ImpexValue): ImpexValueGroup? = PsiTreeUtil
.getParentOfType(element, ImpexValueGroup::class.java)
fun getValueGroup(element: ImpexValueLine, columnNumber: Int): ImpexValueGroup? = element
.childrenOfType<ImpexValueGroup>()
.getOrNull(columnNumber)
fun getAnyAttributeName(element: ImpexAnyAttributeValue): ImpexAnyAttributeName? = PsiTreeUtil
.getPrevSiblingOfType(element, ImpexAnyAttributeName::class.java)
fun getAnyAttributeValue(element: ImpexAnyAttributeName): ImpexAnyAttributeValue? = PsiTreeUtil
.getNextSiblingOfType(element, ImpexAnyAttributeValue::class.java)
fun getUniqueFullHeaderParameters(element: ImpexHeaderLine) = element.fullHeaderParameterList
.filter { it.getAttribute(AttributeModifier.UNIQUE)?.anyAttributeValue?.textMatches("true") ?: false }
fun getTableRange(element: ImpexHeaderLine): TextRange {
val tableElements = ArrayDeque<PsiElement>()
var next = element.nextSibling
while (next != null) {
if (next is ImpexHeaderLine || next is ImpexUserRightsStart) {
// once all lines processed, we have to go back till last value line
var lastElement = tableElements.lastOrNull()
while (lastElement != null && lastElement !is ImpexValueLine) {
tableElements.removeLastOrNull()
lastElement = tableElements.lastOrNull()
}
next = null
} else {
// skip User Rights inside ImpEx statement
if (next !is ImpexUserRights) {
tableElements.add(next)
}
next = next.nextSibling
}
}
val endOffset = tableElements.lastOrNull()
?.endOffset
?: element.endOffset
return TextRange.create(element.startOffset, endOffset)
}
fun addValueGroups(element: ImpexValueLine, groupsToAdd: Int) {
if (groupsToAdd <= 0) return
repeat(groupsToAdd) {
ImpExElementFactory.createValueGroup(element.project)
?.let { element.addAfter(it, element.valueGroupList.lastOrNull()) }
}
}
fun getAttribute(element: ImpexFullHeaderParameter, attributeModifier: AttributeModifier): ImpexAttribute? = element
.modifiersList
.flatMap { it.attributeList }
.find { it.anyAttributeName.textMatches(attributeModifier.modifierName) }
fun getHeaderTypeName(element: ImpexSubTypeName): ImpexHeaderTypeName? = element
.valueLine
?.headerLine
?.fullHeaderType
?.headerTypeName
fun getConfigPropertyKey(element: ImpexMacroUsageDec): String? {
if (!element.text.startsWith(HybrisConstants.IMPEX_CONFIG_COMPLETE_PREFIX)) return null
val project = element.project
val propertyKey = element.text.replace(HybrisConstants.IMPEX_CONFIG_COMPLETE_PREFIX, "")
if (propertyKey.isBlank()) return null
return if (DumbService.isDumb(project)) {
element.text.replace(HybrisConstants.IMPEX_CONFIG_COMPLETE_PREFIX, "")
} else PropertyService.getInstance(project)
?.findMacroProperty(propertyKey)
?.key
?: element.text.replace(HybrisConstants.IMPEX_CONFIG_COMPLETE_PREFIX, "")
}
fun getInlineTypeName(element: ImpexParameter): String? = element.text
// .replace(CompletionUtilCore.DUMMY_IDENTIFIER, "")
.substringBefore("(")
.substringBefore("[")
.trim()
.indexOf('.')
.takeIf { it >= 0 }
?.let { element.text.substring(0, it).trim() }
fun getAttributeName(element: ImpexParameter): String = element.text
// .replace(CompletionUtilCore.DUMMY_IDENTIFIER, "")
.substringBefore("(")
.substringBefore("[")
.substringAfter(".")
.trim()
/**
* 1. Try to get inline `MyType` type: referenceAttr(MyType.attr)
* 2. If not present fallback to a type of the `referenceAttr`: referenceAttr(attr)
*/
fun getItemTypeName(element: ImpexParameter): String? = element
.inlineTypeName
?: element.referenceItemTypeName
fun getReferenceName(element: ImpexParameter): String? = (PsiTreeUtil
.getParentOfType(element, ImpexParameter::class.java)
?: PsiTreeUtil.getParentOfType(element, ImpexFullHeaderParameter::class.java)
?.anyHeaderParameterName)
?.text
fun getReferenceItemTypeName(element: ImpexParameter): String? = (
PsiTreeUtil
.getParentOfType(element, ImpexParameter::class.java)
?: PsiTreeUtil.getParentOfType(element, ImpexFullHeaderParameter::class.java)
?.anyHeaderParameterName
)
?.reference
?.let { it as PsiPolyVariantReference }
?.multiResolve(false)
?.firstOrNull()
?.let {
when (it) {
is AttributeResolveResult -> it.meta.type
is EnumResolveResult -> it.meta.name
is ItemResolveResult -> it.meta.name
is RelationResolveResult -> it.meta.name
is RelationEndResolveResult -> it.meta.type
else -> null
}
}
fun getHeaderItemTypeName(element: ImpexAnyHeaderParameterName): ImpexHeaderTypeName? = PsiTreeUtil
.getParentOfType(element, ImpexHeaderLine::class.java)
?.fullHeaderType
?.headerTypeName
// ------------------------------------------
// User Rights
// ------------------------------------------
fun getValueGroups(element: ImpexUserRights, index: Int): Collection<ImpexUserRightsValueGroup> = element
.userRightsValueLineList
.mapNotNull { it.getValueGroup(index) }
fun getValueGroup(element: ImpexUserRightsValueLine, index: Int): ImpexUserRightsValueGroup? = element
.userRightsValueGroupList
.getOrNull(index)
fun getHeaderParameter(element: ImpexUserRightsHeaderLine, index: Int): ImpexUserRightsHeaderParameter? = element
.userRightsHeaderParameterList
.getOrNull(index)
fun getHeaderLine(element: ImpexUserRightsValueLine): ImpexUserRightsHeaderLine? = PsiTreeUtil
.getPrevSiblingOfType(element, ImpexUserRightsHeaderLine::class.java)
fun getValueLine(element: ImpexUserRightsValueGroup): ImpexUserRightsValueLine? = element
.parentOfType<ImpexUserRightsValueLine>()
fun getValueLine(element: ImpexUserRightsValue): ImpexUserRightsValueLine? = element
.parentOfType<ImpexUserRightsValueLine>()
fun getColumnNumber(element: ImpexUserRightsValueGroup): Int? = element
.valueLine
?.let { valueLine ->
valueLine.userRightsValueGroupList.indexOf(element)
.takeIf { it != -1 }
?.let {
// we always have to plus one column, because a first value group is not part of the list
it + 1
}
}
fun getHeaderParameter(element: ImpexUserRightsValueGroup): ImpexUserRightsHeaderParameter? = element
.columnNumber
?.let {
getValueLine(element)
?.headerLine
?.getHeaderParameter(it)
}
fun getHeaderParameter(element: ImpexUserRightsValue): ImpexUserRightsHeaderParameter? = when (val parent = element.parent) {
is ImpexUserRightsFirstValueGroup -> {
getValueLine(element)
?.headerLine
?.getHeaderParameter(0)
}
is ImpexUserRightsValueGroup -> {
parent
.columnNumber
?.let {
getValueLine(element)
?.headerLine
?.getHeaderParameter(it)
}
}
else -> null
}
fun getHeaderLine(element: ImpexUserRightsHeaderParameter): ImpexUserRightsHeaderLine? = element
.parentOfType<ImpexUserRightsHeaderLine>()
fun getColumnNumber(element: ImpexUserRightsHeaderParameter): Int? = element
.headerLine
?.userRightsHeaderParameterList
?.indexOf(element)
?.takeIf { it != -1 }
fun getValueGroups(element: ImpexUserRightsHeaderParameter): Collection<ImpexUserRightsValueGroup> {
val columnNumber = element.columnNumber ?: return emptyList()
val userRights = getUserRights(element) ?: return emptyList()
return userRights.getValueGroups(columnNumber)
}
fun getUserRights(element: PsiElement): ImpexUserRights? = element
.parentOfType<ImpexUserRights>()