@@ -7,21 +7,20 @@ import com.google.devtools.ksp.getVisibility
7
7
import com.google.devtools.ksp.processing.*
8
8
import com.google.devtools.ksp.symbol.*
9
9
import com.google.devtools.ksp.validate
10
- import com.google.devtools.ksp.visitor.KSDefaultVisitor
11
10
import com.intuit.hooks.plugin.codegen.*
12
- import com.intuit.hooks.plugin.ensure
13
11
import com.intuit.hooks.plugin.ksp.validation.*
14
12
import com.intuit.hooks.plugin.ksp.validation.EdgeCase
15
13
import com.intuit.hooks.plugin.ksp.validation.HookValidationError
16
14
import com.intuit.hooks.plugin.ksp.validation.error
17
15
import com.intuit.hooks.plugin.ksp.validation.validateProperty
16
+ import com.intuit.hooks.plugin.mapOrAccumulate
18
17
import com.intuit.hooks.plugin.raise
19
18
import com.squareup.kotlinpoet.*
20
19
import com.squareup.kotlinpoet.ksp.*
21
20
22
21
public class HooksProcessor (
23
22
private val codeGenerator : CodeGenerator ,
24
- private val logger : KSPLogger ,
23
+ private val logger : KSPLogger
25
24
) : SymbolProcessor {
26
25
27
26
override fun process (resolver : Resolver ): List <KSAnnotated > {
@@ -32,26 +31,18 @@ public class HooksProcessor(
32
31
return emptyList()
33
32
}
34
33
35
- private inner class HookPropertyVisitor : KSDefaultVisitor <TypeParameterResolver , HookInfo >() {
36
-
34
+ private inner class HookPropertyVisitor : KSRaiseVisitor <TypeParameterResolver , HookInfo , HookValidationError >() {
37
35
context(Raise <Nel <HookValidationError >>)
38
- override fun visitPropertyDeclaration (property : KSPropertyDeclaration , parentResolver : TypeParameterResolver ): HookInfo {
39
- ensure(property.modifiers.contains(Modifier .ABSTRACT )) {
40
- HookValidationError .NotAnAbstractProperty (property)
41
- }
42
-
43
- return property.validateProperty(parentResolver)
44
- }
45
-
46
- override fun defaultHandler (node : KSNode , data : TypeParameterResolver ) = error(" Should not happen." )
36
+ override fun visitPropertyDeclaration (property : KSPropertyDeclaration , data : TypeParameterResolver ): HookInfo =
37
+ property.validateProperty(data)
47
38
}
48
39
49
40
private inner class HookFileVisitor : KSVisitorVoid () {
50
41
override fun visitFile (file : KSFile , data : Unit ) {
51
42
recover({
52
43
val containers = file.declarations
53
44
.filterIsInstance<KSClassDeclaration >()
54
- .flatMap { it.accept(HookContainerVisitor (), this ) }
45
+ .flatMap { it.accept(HookContainerVisitor (), Unit ) }
55
46
.ifEmpty { raise(EdgeCase .NoHooksDefined (file)) }
56
47
57
48
val packageName = file.packageName.asString()
@@ -69,45 +60,46 @@ public class HooksProcessor(
69
60
}
70
61
}
71
62
72
- private inner class HookContainerVisitor : KSDefaultVisitor <Raise <Nel <HookValidationError >>, Sequence <HooksContainer >>() {
73
- // TODO: Try with context receiver
74
- override fun visitClassDeclaration (
75
- classDeclaration : KSClassDeclaration ,
76
- raise : Raise <Nel <HookValidationError >>
77
- ): Sequence <HooksContainer > = with (raise) {
63
+ private inner class HookContainerVisitor : KSRaiseVisitor <Unit , Sequence <HooksContainer >, HookValidationError >() {
64
+
65
+ context(Raise <Nel <HookValidationError >>)
66
+ override fun visitClassDeclaration (classDeclaration : KSClassDeclaration , data : Unit ): Sequence <HooksContainer > {
78
67
val superTypeNames = classDeclaration.superTypes
79
68
.filter { it.toString().contains(" Hooks" ) }
80
69
.toList()
81
70
82
71
return if (superTypeNames.isEmpty()) {
83
72
classDeclaration.declarations
84
73
.filter { it is KSClassDeclaration && it.validate() /* TODO: Tie in validations to KSP */ }
85
- .flatMap { it.accept(this @HookContainerVisitor, raise ) }
74
+ .flatMap { it.accept(this @HookContainerVisitor, Unit ) }
86
75
} else if (superTypeNames.any { it.resolve().declaration.qualifiedName?.getQualifier() == " com.intuit.hooks.dsl" }) {
87
76
val parentResolver = classDeclaration.typeParameters.toTypeParameterResolver()
88
77
89
78
classDeclaration.getAllProperties()
90
- .map { it.accept(HookPropertyVisitor (), parentResolver) }
91
- // TODO: Maybe curry class declaration
92
- .run { createHooksContainer(classDeclaration, toList()) }
79
+ .mapOrAccumulate { it.accept(HookPropertyVisitor (), parentResolver) }
80
+ .let { createHooksContainer(classDeclaration, it) }
93
81
.let { sequenceOf(it) }
94
- } else emptySequence()
82
+ } else {
83
+ emptySequence()
84
+ }
95
85
}
96
86
97
- fun ClassKind.toTypeSpecKind (): TypeSpec .Kind = when (this ) {
87
+ context(Raise <Nel <HookValidationError >>)
88
+ fun KSClassDeclaration.toTypeSpecKind (): TypeSpec .Kind = when (classKind) {
98
89
ClassKind .CLASS -> TypeSpec .Kind .CLASS
99
90
ClassKind .INTERFACE -> TypeSpec .Kind .INTERFACE
100
91
ClassKind .OBJECT -> TypeSpec .Kind .OBJECT
101
- else -> throw NotImplementedError ( " Hooks in constructs other than class, interface, and object aren't supported " )
92
+ else -> raise( HookValidationError . UnsupportedContainer ( this ) )
102
93
}
103
94
95
+ context(Raise <Nel <HookValidationError >>)
104
96
fun createHooksContainer (classDeclaration : KSClassDeclaration , hooks : List <HookInfo >): HooksContainer {
105
97
val name =
106
98
" ${classDeclaration.parentDeclaration?.simpleName?.asString() ? : " " }${classDeclaration.simpleName.asString()} Impl"
107
99
val visibilityModifier = classDeclaration.getVisibility().toKModifier() ? : KModifier .PUBLIC
108
100
val typeArguments = classDeclaration.typeParameters.map { it.toTypeVariableName() }
109
101
val className = classDeclaration.toClassName()
110
- val typeSpecKind = classDeclaration.classKind. toTypeSpecKind()
102
+ val typeSpecKind = classDeclaration.toTypeSpecKind()
111
103
112
104
return HooksContainer (
113
105
name,
@@ -118,8 +110,6 @@ public class HooksProcessor(
118
110
hooks
119
111
)
120
112
}
121
-
122
- override fun defaultHandler (node : KSNode , data : Raise <Nel <HookValidationError >>) = TODO (" Not yet implemented" )
123
113
}
124
114
125
115
public class Provider : SymbolProcessorProvider {
0 commit comments