-
Notifications
You must be signed in to change notification settings - Fork 437
/
OpticsProcessor.kt
68 lines (61 loc) · 2.38 KB
/
OpticsProcessor.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
package arrow.optics.plugin
import arrow.optics.plugin.internals.Snippet
import arrow.optics.plugin.internals.adt
import arrow.optics.plugin.internals.asFileText
import arrow.optics.plugin.internals.join
import arrow.optics.plugin.internals.noCompanion
import arrow.optics.plugin.internals.otherClassTypeErrorMessage
import arrow.optics.plugin.internals.qualifiedNameOrSimpleName
import arrow.optics.plugin.internals.snippets
import arrow.optics.plugin.internals.typeParametersErrorMessage
import com.google.devtools.ksp.processing.CodeGenerator
import com.google.devtools.ksp.processing.Dependencies
import com.google.devtools.ksp.processing.KSPLogger
import com.google.devtools.ksp.processing.Resolver
import com.google.devtools.ksp.processing.SymbolProcessor
import com.google.devtools.ksp.symbol.KSAnnotated
import com.google.devtools.ksp.symbol.KSClassDeclaration
class OpticsProcessor(private val codegen: CodeGenerator, private val logger: KSPLogger) :
SymbolProcessor {
override fun process(resolver: Resolver): List<KSAnnotated> {
resolver
.getSymbolsWithAnnotation("arrow.optics.optics")
.filterIsInstance<KSClassDeclaration>()
.forEach(::processClass)
// the docs say that [process] should return
// "deferred symbols that the processor can't process"
// and in theory we have none
return emptyList()
}
private fun processClass(klass: KSClassDeclaration) {
// check that it is sealed or data
if (!klass.isSealed && !klass.isData) {
logger.error(klass.qualifiedNameOrSimpleName.otherClassTypeErrorMessage, klass)
return
}
// check that it does not have type arguments
if (klass.typeParameters.isNotEmpty()) {
logger.error(klass.qualifiedNameOrSimpleName.typeParametersErrorMessage, klass)
return
}
// check that the companion object exists
if (klass.companionObject == null) {
logger.error(klass.qualifiedNameOrSimpleName.noCompanion, klass)
return
}
val adts = adt(klass, logger)
val snippets = adts.snippets()
snippets.groupBy(Snippet::fqName).values.map(List<Snippet>::join).forEach {
val writer =
codegen
.createNewFile(
Dependencies(aggregating = true, *listOfNotNull(klass.containingFile).toTypedArray()),
it.`package`,
it.name
)
.writer()
writer.write(it.asFileText())
writer.flush()
}
}
}