-
Notifications
You must be signed in to change notification settings - Fork 6
/
Hooks.kt
75 lines (63 loc) · 2.75 KB
/
Hooks.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
package com.intuit.hooks.plugin
import arrow.core.*
import arrow.core.extensions.applicativeNel
import arrow.core.extensions.list.traverse.sequence
import arrow.core.extensions.validated.functor.map
import arrow.meta.CliPlugin
import arrow.meta.Meta
import arrow.meta.invoke
import arrow.meta.quotes.Transform
import arrow.meta.quotes.classDeclaration
import arrow.meta.quotes.classorobject.ClassDeclaration
import org.jetbrains.kotlin.psi.KtClass
import org.jetbrains.kotlin.psi.KtImportList
internal val Meta.hooks: CliPlugin
get() =
"Hooks" {
meta(
classDeclaration(this, { this.element.isHooksDslClass }) { c ->
findHooks().map<Transform<KtClass>> { codeGen ->
val `package` = c.element.containingKtFile.packageDirective?.text ?: ""
val (classes, properties) = codeGen.map(::generateHookClass).unzip()
val imports = createImportDirectives(c.element, codeGen)
val newSource =
"""|${`package`}
|
|$imports
|
|$kind ${name}Impl${this.`(typeParameters)`} : $name${this.`(typeParameters)`}() {
| ${properties.map { it.property(null).syntheticElement }.joinToString("\n")}
| ${classes.map { it.`class`.syntheticScope }.joinToString("\n")}
|}""".trimMargin().file("${name}Impl")
Transform.newSources(newSource)
}.valueOr {
reportHookErrors(it)
Transform.empty
}
}
)
}
private fun generateHookClass(hookCodeGen: HookCodeGen): Pair<String, String> {
val classDefinition = hookCodeGen.generateClass()
val propertyDefinition = hookCodeGen.generateProperty()
return classDefinition to propertyDefinition
}
private fun createImportDirectives(c: KtClass, codeGens: List<HookCodeGen>): String {
val existingImports = c.containingKtFile.importList
?.removeHooksDslImport()
?.map { it.text ?: "" }
?: emptyList()
val newImports = codeGens.flatMap { it.generateImports() }
val hookStarImport = listOf("import com.intuit.hooks.*")
return (hookStarImport + existingImports + newImports)
.distinct()
.joinToString("\n")
}
private fun KtImportList.removeHooksDslImport() =
imports.filter { !it.text.contains("com.intuit.hooks.dsl.") }
private fun ClassDeclaration.findHooks() =
body.properties.value
.map(::validateHook)
.sequence(ValidatedNel.applicativeNel())
.map { it.fix() }
.fix()