Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix imports for ksp plugin #2678

Merged
merged 7 commits into from
Mar 8, 2022
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ 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
Expand Down Expand Up @@ -33,19 +34,19 @@ class OpticsProcessor(private val codegen: CodeGenerator, private val logger: KS
private fun processClass(klass: KSClassDeclaration) {
// check that it is sealed or data
if (!klass.isSealed && !klass.isData) {
logger.error(klass.simpleName.asString().otherClassTypeErrorMessage, klass)
logger.error(klass.qualifiedNameOrSimpleName.otherClassTypeErrorMessage, klass)
return
}

// check that it does not have type arguments
if (klass.typeParameters.isNotEmpty()) {
logger.error(klass.simpleName.asString().typeParametersErrorMessage, klass)
logger.error(klass.qualifiedNameOrSimpleName.typeParametersErrorMessage, klass)
return
}

// check that the companion object exists
if (klass.companionObject == null) {
logger.error(klass.simpleName.asString().noCompanion, klass)
logger.error(klass.qualifiedNameOrSimpleName.noCompanion, klass)
return
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,10 @@ import com.google.devtools.ksp.symbol.KSClassDeclaration
import com.google.devtools.ksp.symbol.KSName
import java.util.Locale

data class ADT(val pckg: KSName, val el: KSClassDeclaration, val targets: List<Target>) {
val sourceClassName = el.qualifiedName?.asString() ?: el.simpleName
val sourceName = el.simpleName.asString().replaceFirstChar { it.lowercase(Locale.getDefault()) }
val simpleName = el.simpleName.asString()
val packageName = pckg.asString()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we keep these names the same? This is our own domain.
This introduces a lot of unnecessary changes in the PR.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure

data class ADT(val packageName: KSName, val declaration: KSClassDeclaration, val targets: List<Target>) {
val qualifiedNameOrSimpleName = declaration.qualifiedNameOrSimpleName
val simpleName = declaration.simpleName.asString().replaceFirstChar { it.lowercase(Locale.getDefault()) }
val packageNameAsString = packageName.asString()

operator fun Snippet.plus(snippet: Snippet): Snippet =
copy(imports = imports + snippet.imports, content = "$content\n${snippet.content}")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,37 +2,37 @@ package arrow.optics.plugin.internals

fun generateLensDsl(ele: ADT, optic: DataClassDsl): Snippet =
Snippet(
`package` = ele.packageName,
name = ele.simpleName,
`package` = ele.packageNameAsString,
name = ele.qualifiedNameOrSimpleName,
content = processLensSyntax(ele, optic.foci)
)

fun generateOptionalDsl(ele: ADT, optic: DataClassDsl): Snippet =
Snippet(
`package` = ele.packageName,
name = ele.simpleName,
`package` = ele.packageNameAsString,
name = ele.qualifiedNameOrSimpleName,
content = processOptionalSyntax(ele, optic)
)

fun generatePrismDsl(ele: ADT, isoOptic: SealedClassDsl): Snippet =
Snippet(
`package` = ele.packageName,
name = ele.simpleName,
`package` = ele.packageNameAsString,
name = ele.qualifiedNameOrSimpleName,
content = processPrismSyntax(ele, isoOptic)
)

private fun processLensSyntax(ele: ADT, foci: List<Focus>): String =
foci.joinToString(separator = "\n") { focus ->
"""
|inline val <S> $Iso<S, ${ele.sourceClassName}>.${focus.lensParamName()}: $Lens<S, ${focus.className}> inline get() = this + ${ele.sourceClassName}.${focus.lensParamName()}
|inline val <S> $Lens<S, ${ele.sourceClassName}>.${focus.lensParamName()}: $Lens<S, ${focus.className}> inline get() = this + ${ele.sourceClassName}.${focus.lensParamName()}
|inline val <S> $Optional<S, ${ele.sourceClassName}>.${focus.lensParamName()}: $Optional<S, ${focus.className}> inline get() = this + ${ele.sourceClassName}.${focus.lensParamName()}
|inline val <S> $Prism<S, ${ele.sourceClassName}>.${focus.lensParamName()}: $Optional<S, ${focus.className}> inline get() = this + ${ele.sourceClassName}.${focus.lensParamName()}
|inline val <S> $Getter<S, ${ele.sourceClassName}>.${focus.lensParamName()}: $Getter<S, ${focus.className}> inline get() = this + ${ele.sourceClassName}.${focus.lensParamName()}
|inline val <S> $Setter<S, ${ele.sourceClassName}>.${focus.lensParamName()}: $Setter<S, ${focus.className}> inline get() = this + ${ele.sourceClassName}.${focus.lensParamName()}
|inline val <S> $Traversal<S, ${ele.sourceClassName}>.${focus.lensParamName()}: $Traversal<S, ${focus.className}> inline get() = this + ${ele.sourceClassName}.${focus.lensParamName()}
|inline val <S> $Fold<S, ${ele.sourceClassName}>.${focus.lensParamName()}: $Fold<S, ${focus.className}> inline get() = this + ${ele.sourceClassName}.${focus.lensParamName()}
|inline val <S> $Every<S, ${ele.sourceClassName}>.${focus.lensParamName()}: $Every<S, ${focus.className}> inline get() = this + ${ele.sourceClassName}.${focus.lensParamName()}
|inline val <S> $Iso<S, ${ele.qualifiedNameOrSimpleName}>.${focus.lensParamName()}: $Lens<S, ${focus.className}> inline get() = this + ${ele.qualifiedNameOrSimpleName}.${focus.lensParamName()}
|inline val <S> $Lens<S, ${ele.qualifiedNameOrSimpleName}>.${focus.lensParamName()}: $Lens<S, ${focus.className}> inline get() = this + ${ele.qualifiedNameOrSimpleName}.${focus.lensParamName()}
|inline val <S> $Optional<S, ${ele.qualifiedNameOrSimpleName}>.${focus.lensParamName()}: $Optional<S, ${focus.className}> inline get() = this + ${ele.qualifiedNameOrSimpleName}.${focus.lensParamName()}
|inline val <S> $Prism<S, ${ele.qualifiedNameOrSimpleName}>.${focus.lensParamName()}: $Optional<S, ${focus.className}> inline get() = this + ${ele.qualifiedNameOrSimpleName}.${focus.lensParamName()}
|inline val <S> $Getter<S, ${ele.qualifiedNameOrSimpleName}>.${focus.lensParamName()}: $Getter<S, ${focus.className}> inline get() = this + ${ele.qualifiedNameOrSimpleName}.${focus.lensParamName()}
|inline val <S> $Setter<S, ${ele.qualifiedNameOrSimpleName}>.${focus.lensParamName()}: $Setter<S, ${focus.className}> inline get() = this + ${ele.qualifiedNameOrSimpleName}.${focus.lensParamName()}
|inline val <S> $Traversal<S, ${ele.qualifiedNameOrSimpleName}>.${focus.lensParamName()}: $Traversal<S, ${focus.className}> inline get() = this + ${ele.qualifiedNameOrSimpleName}.${focus.lensParamName()}
|inline val <S> $Fold<S, ${ele.qualifiedNameOrSimpleName}>.${focus.lensParamName()}: $Fold<S, ${focus.className}> inline get() = this + ${ele.qualifiedNameOrSimpleName}.${focus.lensParamName()}
|inline val <S> $Every<S, ${ele.qualifiedNameOrSimpleName}>.${focus.lensParamName()}: $Every<S, ${focus.className}> inline get() = this + ${ele.qualifiedNameOrSimpleName}.${focus.lensParamName()}
|""".trimMargin()
}

Expand All @@ -46,27 +46,27 @@ private fun processOptionalSyntax(ele: ADT, optic: DataClassDsl) =
}

"""
|inline val <S> $Iso<S, ${ele.sourceClassName}>.${focus.paramName}: $Optional<S, $targetClassName> inline get() = this + ${ele.sourceClassName}.${focus.paramName}
|inline val <S> $Lens<S, ${ele.sourceClassName}>.${focus.paramName}: $Optional<S, $targetClassName> inline get() = this + ${ele.sourceClassName}.${focus.paramName}
|inline val <S> $Optional<S, ${ele.sourceClassName}>.${focus.paramName}: $Optional<S, $targetClassName> inline get() = this + ${ele.sourceClassName}.${focus.paramName}
|inline val <S> $Prism<S, ${ele.sourceClassName}>.${focus.paramName}: $Optional<S, $targetClassName> inline get() = this + ${ele.sourceClassName}.${focus.paramName}
|inline val <S> $Setter<S, ${ele.sourceClassName}>.${focus.paramName}: $Setter<S, $targetClassName> inline get() = this + ${ele.sourceClassName}.${focus.paramName}
|inline val <S> $Traversal<S, ${ele.sourceClassName}>.${focus.paramName}: $Traversal<S, $targetClassName> inline get() = this + ${ele.sourceClassName}.${focus.paramName}
|inline val <S> $Fold<S, ${ele.sourceClassName}>.${focus.paramName}: $Fold<S, $targetClassName> inline get() = this + ${ele.sourceClassName}.${focus.paramName}
|inline val <S> $Every<S, ${ele.sourceClassName}>.${focus.paramName}: $Every<S, $targetClassName> inline get() = this + ${ele.sourceClassName}.${focus.paramName}
|inline val <S> $Iso<S, ${ele.qualifiedNameOrSimpleName}>.${focus.paramName}: $Optional<S, $targetClassName> inline get() = this + ${ele.qualifiedNameOrSimpleName}.${focus.paramName}
|inline val <S> $Lens<S, ${ele.qualifiedNameOrSimpleName}>.${focus.paramName}: $Optional<S, $targetClassName> inline get() = this + ${ele.qualifiedNameOrSimpleName}.${focus.paramName}
|inline val <S> $Optional<S, ${ele.qualifiedNameOrSimpleName}>.${focus.paramName}: $Optional<S, $targetClassName> inline get() = this + ${ele.qualifiedNameOrSimpleName}.${focus.paramName}
|inline val <S> $Prism<S, ${ele.qualifiedNameOrSimpleName}>.${focus.paramName}: $Optional<S, $targetClassName> inline get() = this + ${ele.qualifiedNameOrSimpleName}.${focus.paramName}
|inline val <S> $Setter<S, ${ele.qualifiedNameOrSimpleName}>.${focus.paramName}: $Setter<S, $targetClassName> inline get() = this + ${ele.qualifiedNameOrSimpleName}.${focus.paramName}
|inline val <S> $Traversal<S, ${ele.qualifiedNameOrSimpleName}>.${focus.paramName}: $Traversal<S, $targetClassName> inline get() = this + ${ele.qualifiedNameOrSimpleName}.${focus.paramName}
|inline val <S> $Fold<S, ${ele.qualifiedNameOrSimpleName}>.${focus.paramName}: $Fold<S, $targetClassName> inline get() = this + ${ele.qualifiedNameOrSimpleName}.${focus.paramName}
|inline val <S> $Every<S, ${ele.qualifiedNameOrSimpleName}>.${focus.paramName}: $Every<S, $targetClassName> inline get() = this + ${ele.qualifiedNameOrSimpleName}.${focus.paramName}
|""".trimMargin()
}

private fun processPrismSyntax(ele: ADT, dsl: SealedClassDsl): String =
dsl.foci.joinToString(separator = "\n\n") { focus ->
"""
|inline val <S> $Iso<S, ${ele.sourceClassName}>.${focus.paramName}: $Prism<S, ${focus.className}> inline get() = this + ${ele.sourceClassName}.${focus.paramName}
|inline val <S> $Lens<S, ${ele.sourceClassName}>.${focus.paramName}: $Optional<S, ${focus.className}> inline get() = this + ${ele.sourceClassName}.${focus.paramName}
|inline val <S> $Optional<S, ${ele.sourceClassName}>.${focus.paramName}: $Optional<S, ${focus.className}> inline get() = this + ${ele.sourceClassName}.${focus.paramName}
|inline val <S> $Prism<S, ${ele.sourceClassName}>.${focus.paramName}: $Prism<S, ${focus.className}> inline get() = this + ${ele.sourceClassName}.${focus.paramName}
|inline val <S> $Setter<S, ${ele.sourceClassName}>.${focus.paramName}: $Setter<S, ${focus.className}> inline get() = this + ${ele.sourceClassName}.${focus.paramName}
|inline val <S> $Traversal<S, ${ele.sourceClassName}>.${focus.paramName}: $Traversal<S, ${focus.className}> inline get() = this + ${ele.sourceClassName}.${focus.paramName}
|inline val <S> $Fold<S, ${ele.sourceClassName}>.${focus.paramName}: $Fold<S, ${focus.className}> inline get() = this + ${ele.sourceClassName}.${focus.paramName}
|inline val <S> $Every<S, ${ele.sourceClassName}>.${focus.paramName}: $Every<S, ${focus.className}> inline get() = this + ${ele.sourceClassName}.${focus.paramName}
|inline val <S> $Iso<S, ${ele.qualifiedNameOrSimpleName}>.${focus.paramName}: $Prism<S, ${focus.className}> inline get() = this + ${ele.qualifiedNameOrSimpleName}.${focus.paramName}
|inline val <S> $Lens<S, ${ele.qualifiedNameOrSimpleName}>.${focus.paramName}: $Optional<S, ${focus.className}> inline get() = this + ${ele.qualifiedNameOrSimpleName}.${focus.paramName}
|inline val <S> $Optional<S, ${ele.qualifiedNameOrSimpleName}>.${focus.paramName}: $Optional<S, ${focus.className}> inline get() = this + ${ele.qualifiedNameOrSimpleName}.${focus.paramName}
|inline val <S> $Prism<S, ${ele.qualifiedNameOrSimpleName}>.${focus.paramName}: $Prism<S, ${focus.className}> inline get() = this + ${ele.qualifiedNameOrSimpleName}.${focus.paramName}
|inline val <S> $Setter<S, ${ele.qualifiedNameOrSimpleName}>.${focus.paramName}: $Setter<S, ${focus.className}> inline get() = this + ${ele.qualifiedNameOrSimpleName}.${focus.paramName}
|inline val <S> $Traversal<S, ${ele.qualifiedNameOrSimpleName}>.${focus.paramName}: $Traversal<S, ${focus.className}> inline get() = this + ${ele.qualifiedNameOrSimpleName}.${focus.paramName}
|inline val <S> $Fold<S, ${ele.qualifiedNameOrSimpleName}>.${focus.paramName}: $Fold<S, ${focus.className}> inline get() = this + ${ele.qualifiedNameOrSimpleName}.${focus.paramName}
|inline val <S> $Every<S, ${ele.qualifiedNameOrSimpleName}>.${focus.paramName}: $Every<S, ${focus.className}> inline get() = this + ${ele.qualifiedNameOrSimpleName}.${focus.paramName}
|""".trimMargin()
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package arrow.optics.plugin.internals

internal fun generateIsos(ele: ADT, target: IsoTarget) =
Snippet(`package` = ele.packageName, name = ele.simpleName, content = processElement(ele, target))
Snippet(`package` = ele.packageNameAsString, name = ele.qualifiedNameOrSimpleName, content = processElement(ele, target))

inline val Target.targetNames
inline get() = foci.map(Focus::className)
Expand Down Expand Up @@ -34,11 +34,11 @@ private fun processElement(iso: ADT, target: Target): String {
)

fun Focus.format(): String =
"${iso.sourceName}.${paramName.plusIfNotBlank(prefix = "`", postfix = "`")}"
"${iso.simpleName}.${paramName.plusIfNotBlank(prefix = "`", postfix = "`")}"

fun tupleConstructor() =
when (foci.size) {
1 -> "${iso.sourceName}.${foci.first().paramName}"
1 -> "${iso.simpleName}.${foci.first().paramName}"
2 -> "$Pair(${foci[0].format()}, ${foci[1].format()})"
3 -> "$Triple(${foci[0].format()}, ${foci[1].format()}, ${foci[2].format()})"
else ->
Expand All @@ -55,17 +55,17 @@ private fun processElement(iso: ADT, target: Target): String {

fun classConstructorFromTuple() =
when (foci.size) {
1 -> "${iso.sourceClassName}(it)"
2 -> "pair: ${focusType()} -> ${iso.sourceClassName}(pair.first, pair.second)"
1 -> "${iso.qualifiedNameOrSimpleName}(it)"
2 -> "pair: ${focusType()} -> ${iso.qualifiedNameOrSimpleName}(pair.first, pair.second)"
3 ->
"triple: ${focusType()} -> ${iso.sourceClassName}(triple.first, triple.second, triple.third)"
"triple: ${focusType()} -> ${iso.qualifiedNameOrSimpleName}(triple.first, triple.second, triple.third)"
else ->
"tuple: ${focusType()} -> ${(foci.indices).joinToString(prefix = "${iso.sourceClassName}(", postfix = ")", transform = { "tuple.${letters[it]}" })}"
"tuple: ${focusType()} -> ${(foci.indices).joinToString(prefix = "${iso.qualifiedNameOrSimpleName}(", postfix = ")", transform = { "tuple.${letters[it]}" })}"
}

return """
|inline val ${iso.sourceClassName}.Companion.iso: $Iso<${iso.sourceClassName}, ${focusType()}> inline get()= $Iso(
| get = { ${iso.sourceName}: ${iso.sourceClassName} -> ${tupleConstructor()} },
|inline val ${iso.qualifiedNameOrSimpleName}.Companion.iso: $Iso<${iso.qualifiedNameOrSimpleName}, ${focusType()}> inline get()= $Iso(
| get = { ${iso.simpleName}: ${iso.qualifiedNameOrSimpleName} -> ${tupleConstructor()} },
| reverseGet = { ${classConstructorFromTuple()} }
|)
|""".trimMargin()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import java.util.Locale

internal fun generateLenses(ele: ADT, target: LensTarget) =
Snippet(
`package` = ele.packageName,
name = ele.simpleName,
`package` = ele.packageNameAsString,
name = ele.qualifiedNameOrSimpleName,
content = processElement(ele, target.foci)
)

Expand All @@ -20,12 +20,22 @@ private fun String.toUpperCamelCase(): String =
}
)

private fun processElement(ele: ADT, foci: List<Focus>): String =
private fun processElement(adt: ADT, foci: List<Focus>): String =
foci.joinToString(separator = "\n") { focus ->
"""
|inline val ${ele.sourceClassName}.Companion.${focus.lensParamName()}: $Lens<${ele.sourceClassName}, ${focus.className}> inline get()= $Lens(
| get = { ${ele.sourceName}: ${ele.sourceClassName} -> ${ele.sourceName}.${focus.paramName.plusIfNotBlank(prefix = "`", postfix = "`")} },
| set = { ${ele.sourceName}: ${ele.sourceClassName}, value: ${focus.className} -> ${ele.sourceName}.copy(${focus.paramName.plusIfNotBlank(prefix = "`", postfix = "`")} = value) }
|inline val ${adt.qualifiedNameOrSimpleName}.Companion.${focus.lensParamName()}: $Lens<${adt.qualifiedNameOrSimpleName}, ${focus.className}> inline get()= $Lens(
| get = { ${adt.simpleName}: ${adt.qualifiedNameOrSimpleName} -> ${adt.simpleName}.${
focus.paramName.plusIfNotBlank(
prefix = "`",
postfix = "`"
)
} },
nomisRev marked this conversation as resolved.
Show resolved Hide resolved
| set = { ${adt.simpleName}: ${adt.qualifiedNameOrSimpleName}, value: ${focus.className} -> ${adt.simpleName}.copy(${
focus.paramName.plusIfNotBlank(
prefix = "`",
postfix = "`"
)
} = value) }
|)
|""".trimMargin()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ package arrow.optics.plugin.internals

internal fun generateOptionals(ele: ADT, target: OptionalTarget) =
Snippet(
`package` = ele.packageName,
name = ele.simpleName,
`package` = ele.packageNameAsString,
name = ele.qualifiedNameOrSimpleName,
imports =
setOf("import arrow.core.left", "import arrow.core.right", "import arrow.core.toOption"),
content = processElement(ele, target.foci)
Expand All @@ -12,9 +12,14 @@ internal fun generateOptionals(ele: ADT, target: OptionalTarget) =
private fun processElement(ele: ADT, foci: List<Focus>): String =
foci.joinToString(separator = "\n") { focus ->
fun getOrModifyF(toNullable: String = "") =
"{ ${ele.sourceName}: ${ele.sourceClassName} -> ${ele.sourceName}.${focus.paramName.plusIfNotBlank(prefix = "`", postfix = "`")}$toNullable?.right() ?: ${ele.sourceName}.left() }"
"{ ${ele.simpleName}: ${ele.qualifiedNameOrSimpleName} -> ${ele.simpleName}.${
focus.paramName.plusIfNotBlank(
prefix = "`",
postfix = "`"
)
}$toNullable?.right() ?: ${ele.simpleName}.left() }"
fun setF(fromNullable: String = "") =
"${ele.sourceName}.copy(${focus.paramName.plusIfNotBlank(prefix = "`", postfix = "`")} = value$fromNullable)"
"${ele.simpleName}.copy(${focus.paramName.plusIfNotBlank(prefix = "`", postfix = "`")} = value$fromNullable)"

val (targetClassName, getOrModify, set) =
when (focus) {
Expand All @@ -25,9 +30,9 @@ private fun processElement(ele: ADT, foci: List<Focus>): String =
}

"""
|inline val ${ele.sourceClassName}.Companion.${focus.paramName}: $Optional<${ele.sourceClassName}, $targetClassName> inline get()= $Optional(
|inline val ${ele.qualifiedNameOrSimpleName}.Companion.${focus.paramName}: $Optional<${ele.qualifiedNameOrSimpleName}, $targetClassName> inline get()= $Optional(
| getOrModify = $getOrModify,
| set = { ${ele.sourceName}: ${ele.sourceClassName}, value: $targetClassName -> $set }
| set = { ${ele.simpleName}: ${ele.qualifiedNameOrSimpleName}, value: $targetClassName -> $set }
|)
|""".trimMargin()
}
Loading