Skip to content

Commit

Permalink
feat: Apply field rules to getter and setter methods (#1044)
Browse files Browse the repository at this point in the history
  • Loading branch information
tangcent authored Oct 17, 2023
1 parent b9fbfee commit 0638498
Show file tree
Hide file tree
Showing 13 changed files with 330 additions and 154 deletions.
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ plugin_version=2.6.3.212.0
kotlin.code.style=official
kotlin_version=1.8.0
junit_version=5.9.2
itangcent_intellij_version=1.5.6
itangcent_intellij_version=1.5.7
Original file line number Diff line number Diff line change
Expand Up @@ -230,16 +230,6 @@ object ClassExportRuleKeys {
EventRuleMode.THROW_IN_ERROR
)

val JSON_METHOD_PARSE_BEFORE: RuleKey<Boolean> = SimpleRuleKey(
"json.method.parse.before", arrayOf("method.parse.before"),
EventRuleMode.THROW_IN_ERROR
)

val JSON_METHOD_PARSE_AFTER: RuleKey<Boolean> = SimpleRuleKey(
"json.method.parse.after", arrayOf("method.parse.after"),
EventRuleMode.THROW_IN_ERROR
)

val JSON_ADDITIONAL_FIELD: RuleKey<String> = SimpleRuleKey(
"json.additional.field",
StringRuleMode.MERGE_DISTINCT
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,13 @@ import com.itangcent.common.utils.notNullOrEmpty
import com.itangcent.common.utils.sub
import com.itangcent.idea.plugin.api.export.AdditionalField
import com.itangcent.idea.utils.CustomizedPsiClassHelper
import com.itangcent.intellij.config.rule.computer
import com.itangcent.intellij.context.ActionContext
import com.itangcent.intellij.extend.guice.PostConstruct
import com.itangcent.intellij.jvm.duck.DuckType
import com.itangcent.intellij.jvm.AccessibleField
import com.itangcent.intellij.jvm.element.ExplicitClass
import com.itangcent.intellij.jvm.element.ExplicitElement
import com.itangcent.intellij.psi.ContextSwitchListener
import com.itangcent.intellij.psi.ResolveContext
import com.itangcent.intellij.psi.computer

/**
* support rules:
Expand All @@ -38,35 +37,40 @@ class YapiPsiClassHelper : CustomizedPsiClassHelper() {
}
}

override fun afterParseFieldOrMethod(
fieldName: String,
fieldType: DuckType,
fieldOrMethod: ExplicitElement<*>,
override fun afterParseField(
accessibleField: AccessibleField,
resourcePsiClass: ExplicitClass,
resolveContext: ResolveContext,
fields: MutableMap<String, Any?>,
) {
//compute `field.mock`
ruleComputer.computer(YapiClassExportRuleKeys.FIELD_MOCK, fieldOrMethod)
ruleComputer.computer(YapiClassExportRuleKeys.FIELD_MOCK, accessibleField)
?.takeIf { it.isNotBlank() }
?.let { if (resolveProperty) configReader.resolveProperty(it) else it }
?.let { mockInfo ->
fields.sub(Attrs.MOCK_ATTR)[fieldName] = mockInfo
fields.sub(Attrs.MOCK_ATTR)[accessibleField.jsonFieldName()] = mockInfo
parseAsFieldValue(mockInfo)
?.also { KVUtils.useFieldAsAttr(it, Attrs.MOCK_ATTR) }
?.let { populateFieldValue(fieldName, fieldType, fields, it) }
?.let {
populateFieldValue(
accessibleField.jsonFieldName(),
accessibleField.jsonFieldType(),
fields,
it
)
}
}

//compute `field.advanced`
val advancedValue = ruleComputer.computer(
YapiClassExportRuleKeys.FIELD_ADVANCED,
fieldOrMethod
accessibleField
)
if (advancedValue.notNullOrEmpty()) {
fields.sub(Attrs.ADVANCED_ATTR)[fieldName] = advancedValue
fields.sub(Attrs.ADVANCED_ATTR)[accessibleField.jsonFieldName()] = advancedValue
}

super.afterParseFieldOrMethod(fieldName, fieldType, fieldOrMethod, resourcePsiClass, resolveContext, fields)
super.afterParseField(accessibleField, resourcePsiClass, resolveContext, fields)
}

override fun resolveAdditionalField(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,46 @@
package com.itangcent.idea.plugin.rule

import com.itangcent.common.utils.notNullOrEmpty
import com.itangcent.intellij.config.rule.RuleChain
import com.itangcent.intellij.config.rule.RuleMode
import com.itangcent.intellij.config.rule.asSequence
import kotlin.reflect.KClass

enum class MyStringRuleMode : RuleMode<String> {
LIST {
override fun compute(rules: RuleChain<String>): Any? {
return rules
.asSequence()
.map { it.compute() }
.filter { it.notNullOrEmpty() }
override fun compute(rules: RuleChain<String>): Any {
return (rules as RuleChain<Any>)
.mapNotNull { it() }
.flatMap {
it.flatten()
}
.mapNotNull { it as? String }
.filter { it.isNotEmpty() }
.toList()
}
};

override fun targetType(): KClass<String> {
return String::class
}

companion object {
private fun Any?.flatten(): List<Any?> {
return when (this) {
null -> {
emptyList()
}

is Array<*> -> {
this.toList().flatten()
}

is Collection<*> -> {
this.flatMap { it.flatten() }
}

else -> {
listOf(this)
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,18 +14,16 @@ import com.itangcent.intellij.config.ConfigReader
import com.itangcent.intellij.config.rule.RuleComputeListener
import com.itangcent.intellij.config.rule.RuleContext
import com.itangcent.intellij.config.rule.RuleKey
import com.itangcent.intellij.config.rule.computer
import com.itangcent.intellij.extend.guice.PostConstruct
import com.itangcent.intellij.jvm.AccessibleField
import com.itangcent.intellij.jvm.JsonOption
import com.itangcent.intellij.jvm.JsonOption.has
import com.itangcent.intellij.jvm.duck.DuckType
import com.itangcent.intellij.jvm.duck.SingleDuckType
import com.itangcent.intellij.jvm.element.ExplicitClass
import com.itangcent.intellij.jvm.element.ExplicitElement
import com.itangcent.intellij.jvm.element.ExplicitMethod
import com.itangcent.intellij.psi.ClassRuleKeys
import com.itangcent.intellij.psi.DefaultPsiClassHelper
import com.itangcent.intellij.psi.ResolveContext
import com.itangcent.intellij.psi.computer
import java.util.*

/**
Expand Down Expand Up @@ -54,7 +52,11 @@ open class ContextualPsiClassHelper : DefaultPsiClassHelper() {
(ruleComputeListener as? RuleComputeListenerRegistry)?.register(InnerComputeListener())
}

override fun beforeParseClass(psiClass: PsiClass, resolveContext: ResolveContext, fields: MutableMap<String, Any?>) {
override fun beforeParseClass(
psiClass: PsiClass,
resolveContext: ResolveContext,
fields: MutableMap<String, Any?>
) {
tryInitParseContext()
ruleComputer.computer(ClassExportRuleKeys.JSON_CLASS_PARSE_BEFORE, psiClass)
super.beforeParseClass(psiClass, resolveContext, fields)
Expand Down Expand Up @@ -120,22 +122,21 @@ open class ContextualPsiClassHelper : DefaultPsiClassHelper() {
}
}

override fun beforeParseFieldOrMethod(
fieldName: String,
fieldType: DuckType,
fieldOrMethod: ExplicitElement<*>,
override fun beforeParseField(
accessField: AccessibleField,
resourcePsiClass: ExplicitClass,
resolveContext: ResolveContext,
fields: MutableMap<String, Any?>,
): Boolean {
pushField(fieldName)
if (fieldOrMethod is ExplicitMethod) {
ruleComputer.computer(ClassExportRuleKeys.JSON_METHOD_PARSE_BEFORE, fieldOrMethod)
} else {
ruleComputer.computer(ClassExportRuleKeys.JSON_FIELD_PARSE_BEFORE, fieldOrMethod)
}
pushField(accessField.jsonFieldName())
ruleComputer.computer(ClassExportRuleKeys.JSON_FIELD_PARSE_BEFORE, accessField)

return super.beforeParseFieldOrMethod(fieldName, fieldType, fieldOrMethod, resourcePsiClass, resolveContext, fields)
return super.beforeParseField(
accessField,
resourcePsiClass,
resolveContext,
fields
)
}

private fun pushField(fieldName: String) {
Expand All @@ -145,35 +146,37 @@ open class ContextualPsiClassHelper : DefaultPsiClassHelper() {
}
}

override fun onIgnoredParseFieldOrMethod(
fieldName: String,
fieldType: DuckType,
fieldOrMethod: ExplicitElement<*>,
override fun onIgnoredParseField(
accessibleField: AccessibleField,
resourcePsiClass: ExplicitClass,
resolveContext: ResolveContext,
fields: MutableMap<String, Any?>,
fields: MutableMap<String, Any?>
) {
super.onIgnoredParseFieldOrMethod(fieldName, fieldType, fieldOrMethod, resourcePsiClass, resolveContext, fields)
popField(fieldName)
super.onIgnoredParseField(
accessibleField,
resourcePsiClass,
resolveContext,
fields
)
popField(accessibleField.jsonFieldName())
}

override fun afterParseFieldOrMethod(
fieldName: String,
fieldType: DuckType,
fieldOrMethod: ExplicitElement<*>,
override fun afterParseField(
accessibleField: AccessibleField,
resourcePsiClass: ExplicitClass,
resolveContext: ResolveContext,
fields: MutableMap<String, Any?>,
) {
super.afterParseFieldOrMethod(fieldName, fieldType, fieldOrMethod, resourcePsiClass, resolveContext, fields)
super.afterParseField(
accessibleField,
resourcePsiClass,
resolveContext,
fields
)

if (fieldOrMethod is ExplicitMethod) {
ruleComputer.computer(ClassExportRuleKeys.JSON_METHOD_PARSE_AFTER, fieldOrMethod)
} else {
ruleComputer.computer(ClassExportRuleKeys.JSON_FIELD_PARSE_AFTER, fieldOrMethod)
}
popField(fieldName)
computeAdditionalField(fieldOrMethod.psi(), resolveContext, fields)
ruleComputer.computer(ClassExportRuleKeys.JSON_FIELD_PARSE_AFTER, accessibleField)
popField(accessibleField.jsonFieldName())
computeAdditionalField(accessibleField.psi, resolveContext, fields)
}

protected open fun computeAdditionalField(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,14 @@ import com.itangcent.common.utils.*
import com.itangcent.idea.plugin.api.export.AdditionalField
import com.itangcent.idea.plugin.api.export.core.ClassExportRuleKeys
import com.itangcent.idea.plugin.settings.EventRecords
import com.itangcent.intellij.config.rule.computer
import com.itangcent.intellij.extend.toPrettyString
import com.itangcent.intellij.jvm.AccessibleField
import com.itangcent.intellij.jvm.PsiExpressionResolver
import com.itangcent.intellij.jvm.duck.DuckType
import com.itangcent.intellij.jvm.element.ExplicitClass
import com.itangcent.intellij.jvm.element.ExplicitElement
import com.itangcent.intellij.jvm.element.ExplicitField
import com.itangcent.intellij.psi.ObjectHolder
import com.itangcent.intellij.psi.ResolveContext
import com.itangcent.intellij.psi.computer
import com.itangcent.intellij.psi.getOrResolve
import com.itangcent.utils.isCollections

Expand All @@ -33,46 +32,44 @@ open class CustomizedPsiClassHelper : ContextualPsiClassHelper() {
@Inject
private lateinit var psiExpressionResolver: PsiExpressionResolver

override fun afterParseFieldOrMethod(
fieldName: String,
fieldType: DuckType,
fieldOrMethod: ExplicitElement<*>,
override fun afterParseField(
accessibleField: AccessibleField,
resourcePsiClass: ExplicitClass,
resolveContext: ResolveContext,
fields: MutableMap<String, Any?>,
) {
//compute `field.required`
ruleComputer.computer(ClassExportRuleKeys.FIELD_REQUIRED, fieldOrMethod)?.let { required ->
fields.sub(Attrs.REQUIRED_ATTR)[fieldName] = required
ruleComputer.computer(ClassExportRuleKeys.FIELD_REQUIRED, accessibleField)?.let { required ->
fields.sub(Attrs.REQUIRED_ATTR)[accessibleField.jsonFieldName()] = required
}

//compute `field.default.value`
val defaultValue = ruleComputer.computer(ClassExportRuleKeys.FIELD_DEFAULT_VALUE, fieldOrMethod)
val defaultValue = ruleComputer.computer(ClassExportRuleKeys.FIELD_DEFAULT_VALUE, accessibleField)
if (defaultValue.isNullOrEmpty()) {
if (fieldOrMethod is ExplicitField) {
fieldOrMethod.psi().initializer?.let { psiExpressionResolver.process(it) }?.toPrettyString()
?.let { fields.sub(Attrs.DEFAULT_VALUE_ATTR)[fieldName] = it }
accessibleField.field?.psi()?.let { field ->
field.initializer?.let { psiExpressionResolver.process(it) }?.toPrettyString()
?.let { fields.sub(Attrs.DEFAULT_VALUE_ATTR)[accessibleField.jsonFieldName()] = it }
}
} else {
fields.sub(Attrs.DEFAULT_VALUE_ATTR)[fieldName] = defaultValue
fields.sub(Attrs.DEFAULT_VALUE_ATTR)[accessibleField.jsonFieldName()] = defaultValue
parseAsFieldValue(defaultValue)
?.also { KVUtils.useFieldAsAttr(it, Attrs.DEFAULT_VALUE_ATTR) }
?.let { populateFieldValue(fieldName, fieldType, fields, it) }
?.let { populateFieldValue(accessibleField.jsonFieldName(), accessibleField.jsonFieldType(), fields, it) }
}

//compute `field.demo`
val demoValue = ruleComputer.computer(
ClassExportRuleKeys.FIELD_DEMO,
fieldOrMethod
accessibleField
)
if (demoValue.notNullOrBlank()) {
fields.sub(Attrs.DEMO_ATTR)[fieldName] = demoValue
fields.sub(Attrs.DEMO_ATTR)[accessibleField.jsonFieldName()] = demoValue
demoValue?.let { parseAsFieldValue(it) }
?.also { KVUtils.useFieldAsAttr(it, Attrs.DEMO_ATTR) }
?.let { populateFieldValue(fieldName, fieldType, fields, it) }
?.let { populateFieldValue(accessibleField.jsonFieldName(), accessibleField.jsonFieldType(), fields, it) }
}

super.afterParseFieldOrMethod(fieldName, fieldType, fieldOrMethod, resourcePsiClass, resolveContext, fields)
super.afterParseField(accessibleField, resourcePsiClass, resolveContext, fields)
}

override fun resolveAdditionalField(
Expand Down
Loading

0 comments on commit 0638498

Please sign in to comment.