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

Swift ソースコード作成 #27

Merged
merged 12 commits into from
Aug 13, 2024
1 change: 1 addition & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ repositories {
dependencies {
implementation(libs.kaml)
implementation(libs.kotlin.poet)
implementation(libs.swift.poet)
testImplementation(kotlin("test"))
testImplementation(libs.junit)
}
Expand Down
1 change: 1 addition & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ kotlin = "2.0.0"
junit = "junit:junit:4.13.2"
kaml = "com.charleskorn.kaml:kaml:0.60.0"
kotlin-poet = "com.squareup:kotlinpoet:1.18.1"
swift-poet = "io.outfoxx:swiftpoet:1.6.5"
[plugins]
spotless = { id = "com.diffplug.spotless", version = "6.25.0" }
serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
1 change: 1 addition & 0 deletions src/main/kotlin/com/tfandkusu/ga913yaml/KotlinGenerator.kt
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,7 @@ object KotlinGenerator {
private fun generateActionScreenClass(screen: Screen): TypeSpec =
TypeSpec
.objectBuilder(screen.className)
.addKdoc(screen.description)
.apply {
screen.actions.forEach { action ->
addType(
Expand Down
1 change: 1 addition & 0 deletions src/main/kotlin/com/tfandkusu/ga913yaml/Main.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ fun main(args: Array<String>) {
}
"make" -> {
val screens = YamlParser.parse()
SwiftGenerator.generate(screens)
KotlinGenerator.generate(screens)
}
else -> println("Unknown command")
Expand Down
203 changes: 203 additions & 0 deletions src/main/kotlin/com/tfandkusu/ga913yaml/SwiftGenerator.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
package com.tfandkusu.ga913yaml

import com.tfandkusu.ga913yaml.model.Action
import com.tfandkusu.ga913yaml.model.ParameterType
import com.tfandkusu.ga913yaml.model.Screen
import io.outfoxx.swiftpoet.ANY
import io.outfoxx.swiftpoet.BOOL
import io.outfoxx.swiftpoet.DICTIONARY
import io.outfoxx.swiftpoet.DOUBLE
import io.outfoxx.swiftpoet.DeclaredTypeName
import io.outfoxx.swiftpoet.FLOAT
import io.outfoxx.swiftpoet.FileSpec
import io.outfoxx.swiftpoet.FunctionSpec
import io.outfoxx.swiftpoet.INT
import io.outfoxx.swiftpoet.INT64
import io.outfoxx.swiftpoet.PropertySpec
import io.outfoxx.swiftpoet.STRING
import io.outfoxx.swiftpoet.TypeSpec
import io.outfoxx.swiftpoet.parameterizedBy
import java.io.File
import java.nio.file.Files
import java.nio.file.Paths

object SwiftGenerator {
private const val ROOT_STRUCT = "AnalyticsEvent"
private const val DIRECTORY = "ga913-ios/Landmarks/Analytics"
private val SCREEN_PROTOCOL = DeclaredTypeName.typeName(".AnalyticsEventScreen")
private val ACTION_PROTOCOL = DeclaredTypeName.typeName(".AnalyticsEventAction")
private const val EVENT_NAME_PROPERTY = "eventName"
private const val EVENT_PARAMETERS_PROPERTY = "eventParameters"
private const val IS_CONVERSION_EVENT_PROPERTY = "isConversionEvent"

fun generate(screens: List<Screen>) {
val fileSpec =
FileSpec
.builder(ROOT_STRUCT)
.addComment("https://github.com/tfandkusu/ga913-yaml/ による自動生成コードです。編集しないでください。")
.addType(
generateAnalyticsEventScreenProtocol(),
).addType(
generateAnalyticsEventActionProtocol(),
).addType(
TypeSpec
.structBuilder(ROOT_STRUCT)
.addDoc("Analytics イベント構造体群")
.addType(
generateScreenStruct(screens),
).addType(
generateActionStruct(screens),
).build(),
).build()
Files.createDirectories(Paths.get(DIRECTORY))
File("$DIRECTORY/$ROOT_STRUCT.swift").writeText(fileSpec.toString())
}

private fun generateAnalyticsEventScreenProtocol(): TypeSpec =
TypeSpec
.protocolBuilder(SCREEN_PROTOCOL)
.addDoc("画面遷移イベントのプロトコル")
.addProperty(
PropertySpec
.abstractBuilder(EVENT_NAME_PROPERTY, STRING)
.abstractGetter()
.addDoc("Analytics イベント名")
.build(),
).addProperty(
PropertySpec
.abstractBuilder(IS_CONVERSION_EVENT_PROPERTY, BOOL)
.abstractGetter()
.addDoc("コンバージョンイベントフラグ")
.build(),
).build()

private fun generateAnalyticsEventActionProtocol(): TypeSpec =
TypeSpec
.protocolBuilder(ACTION_PROTOCOL)
.addDoc("画面内操作イベントのプロトコル")
.addProperty(
PropertySpec
.abstractBuilder(EVENT_NAME_PROPERTY, STRING)
.abstractGetter()
.addDoc("Analytics イベント名")
.build(),
).addProperty(
PropertySpec
.abstractBuilder(EVENT_PARAMETERS_PROPERTY, DICTIONARY.parameterizedBy(STRING, ANY))
.abstractGetter()
.addDoc("Analytics イベントパラメータ")
.build(),
).addProperty(
PropertySpec
.abstractBuilder(IS_CONVERSION_EVENT_PROPERTY, BOOL)
.abstractGetter()
.addDoc("コンバージョンイベントフラグ")
.build(),
).build()

private fun generateScreenStruct(screens: List<Screen>): TypeSpec =
TypeSpec
.structBuilder("Screen")
.addDoc("画面遷移イベント構造体群")
.apply {
screens.forEach { screen ->
addType(
generateScreenStruct(screen),
)
}
}.build()

private fun generateScreenStruct(screen: Screen): TypeSpec =
TypeSpec
.structBuilder(screen.className)
.addDoc(screen.description)
.addSuperType(SCREEN_PROTOCOL)
.addProperty(
PropertySpec
.builder(EVENT_NAME_PROPERTY, STRING)
.initializer("%S", screen.eventName)
.build(),
).addProperty(
PropertySpec
.builder(IS_CONVERSION_EVENT_PROPERTY, BOOL)
.initializer("%L", screen.isConversionEvent)
.build(),
).build()

private fun generateActionStruct(screens: List<Screen>): TypeSpec =
TypeSpec
.structBuilder("Action")
.addDoc("画面内操作イベント構造体群")
.apply {
screens.forEach { screen ->
addType(
generateActionScreenStruct(screen),
)
}
}.build()

private fun generateActionScreenStruct(screen: Screen): TypeSpec =
TypeSpec
.structBuilder(screen.className)
.addDoc(screen.description)
.apply {
screen.actions.forEach { action ->
addType(generateActionStruct(screenEventName = screen.eventName, action = action))
}
}.build()

private fun generateActionStruct(
screenEventName: String,
action: Action,
): TypeSpec =
TypeSpec
.structBuilder(action.className)
.addDoc(action.description)
.addSuperType(ACTION_PROTOCOL)
.addFunction(
FunctionSpec
.constructorBuilder()
.apply {
action.parameters.forEach { parameter ->
addParameter(parameter.propertyName, toDeclaredTypeNames(parameter.type))
}
if (action.parameters.isEmpty()) {
addStatement("eventParameters = [:]")
} else {
addStatement("eventParameters = [")
action.parameters.forEach { parameter ->
addStatement(
" %S: %L,",
parameter.eventParameterKey,
parameter.propertyName,
)
}
addStatement("]")
}
}.build(),
).addProperty(
PropertySpec
.builder(EVENT_NAME_PROPERTY, STRING)
.initializer("%S", screenEventName + action.eventName)
.build(),
).addProperty(
PropertySpec
.builder(EVENT_PARAMETERS_PROPERTY, DICTIONARY.parameterizedBy(STRING, ANY))
.build(),
).addProperty(
PropertySpec
.builder(IS_CONVERSION_EVENT_PROPERTY, BOOL)
.initializer("%L", action.isConversionEvent)
.build(),
).build()

private fun toDeclaredTypeNames(parameterType: ParameterType): DeclaredTypeName =
when (parameterType) {
ParameterType.STRING -> STRING
ParameterType.INT -> INT
ParameterType.LONG -> INT64
ParameterType.FLOAT -> FLOAT
ParameterType.DOUBLE -> DOUBLE
ParameterType.BOOLEAN -> BOOL
}
}
Loading