@@ -7,21 +7,20 @@ import com.google.devtools.ksp.getVisibility
77import com.google.devtools.ksp.processing.*
88import com.google.devtools.ksp.symbol.*
99import com.google.devtools.ksp.validate
10- import com.google.devtools.ksp.visitor.KSDefaultVisitor
1110import com.intuit.hooks.plugin.codegen.*
12- import com.intuit.hooks.plugin.ensure
1311import com.intuit.hooks.plugin.ksp.validation.*
1412import com.intuit.hooks.plugin.ksp.validation.EdgeCase
1513import com.intuit.hooks.plugin.ksp.validation.HookValidationError
1614import com.intuit.hooks.plugin.ksp.validation.error
1715import com.intuit.hooks.plugin.ksp.validation.validateProperty
16+ import com.intuit.hooks.plugin.mapOrAccumulate
1817import com.intuit.hooks.plugin.raise
1918import com.squareup.kotlinpoet.*
2019import com.squareup.kotlinpoet.ksp.*
2120
2221public class HooksProcessor (
2322 private val codeGenerator : CodeGenerator ,
24- private val logger : KSPLogger ,
23+ private val logger : KSPLogger
2524) : SymbolProcessor {
2625
2726 override fun process (resolver : Resolver ): List <KSAnnotated > {
@@ -32,26 +31,18 @@ public class HooksProcessor(
3231 return emptyList()
3332 }
3433
35- private inner class HookPropertyVisitor : KSDefaultVisitor <TypeParameterResolver , HookInfo >() {
36-
34+ private inner class HookPropertyVisitor : KSRaiseVisitor <TypeParameterResolver , HookInfo , HookValidationError >() {
3735 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)
4738 }
4839
4940 private inner class HookFileVisitor : KSVisitorVoid () {
5041 override fun visitFile (file : KSFile , data : Unit ) {
5142 recover({
5243 val containers = file.declarations
5344 .filterIsInstance<KSClassDeclaration >()
54- .flatMap { it.accept(HookContainerVisitor (), this ) }
45+ .flatMap { it.accept(HookContainerVisitor (), Unit ) }
5546 .ifEmpty { raise(EdgeCase .NoHooksDefined (file)) }
5647
5748 val packageName = file.packageName.asString()
@@ -69,45 +60,46 @@ public class HooksProcessor(
6960 }
7061 }
7162
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 > {
7867 val superTypeNames = classDeclaration.superTypes
7968 .filter { it.toString().contains(" Hooks" ) }
8069 .toList()
8170
8271 return if (superTypeNames.isEmpty()) {
8372 classDeclaration.declarations
8473 .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 ) }
8675 } else if (superTypeNames.any { it.resolve().declaration.qualifiedName?.getQualifier() == " com.intuit.hooks.dsl" }) {
8776 val parentResolver = classDeclaration.typeParameters.toTypeParameterResolver()
8877
8978 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) }
9381 .let { sequenceOf(it) }
94- } else emptySequence()
82+ } else {
83+ emptySequence()
84+ }
9585 }
9686
97- fun ClassKind.toTypeSpecKind (): TypeSpec .Kind = when (this ) {
87+ context(Raise <Nel <HookValidationError >>)
88+ fun KSClassDeclaration.toTypeSpecKind (): TypeSpec .Kind = when (classKind) {
9889 ClassKind .CLASS -> TypeSpec .Kind .CLASS
9990 ClassKind .INTERFACE -> TypeSpec .Kind .INTERFACE
10091 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 ) )
10293 }
10394
95+ context(Raise <Nel <HookValidationError >>)
10496 fun createHooksContainer (classDeclaration : KSClassDeclaration , hooks : List <HookInfo >): HooksContainer {
10597 val name =
10698 " ${classDeclaration.parentDeclaration?.simpleName?.asString() ? : " " }${classDeclaration.simpleName.asString()} Impl"
10799 val visibilityModifier = classDeclaration.getVisibility().toKModifier() ? : KModifier .PUBLIC
108100 val typeArguments = classDeclaration.typeParameters.map { it.toTypeVariableName() }
109101 val className = classDeclaration.toClassName()
110- val typeSpecKind = classDeclaration.classKind. toTypeSpecKind()
102+ val typeSpecKind = classDeclaration.toTypeSpecKind()
111103
112104 return HooksContainer (
113105 name,
@@ -118,8 +110,6 @@ public class HooksProcessor(
118110 hooks
119111 )
120112 }
121-
122- override fun defaultHandler (node : KSNode , data : Raise <Nel <HookValidationError >>) = TODO (" Not yet implemented" )
123113 }
124114
125115 public class Provider : SymbolProcessorProvider {
0 commit comments