diff --git a/buildSrc/src/main/kotlin/dev/adamko/kafkatorio/lang/node.gradle.kts b/buildSrc/src/main/kotlin/dev/adamko/kafkatorio/lang/node.gradle.kts index a32586f..8e07427 100644 --- a/buildSrc/src/main/kotlin/dev/adamko/kafkatorio/lang/node.gradle.kts +++ b/buildSrc/src/main/kotlin/dev/adamko/kafkatorio/lang/node.gradle.kts @@ -3,12 +3,15 @@ package dev.adamko.kafkatorio.lang import com.github.gradle.node.npm.task.NpmInstallTask import dev.adamko.kafkatorio.Versions import dev.adamko.kafkatorio.task.UpdatePackageJson +import kotlinx.serialization.json.put + plugins { id("com.github.node-gradle.node") id("dev.adamko.kafkatorio.base") } + node { download.set(true) version.set(Versions.node) @@ -23,7 +26,11 @@ val updatePackageJson by tasks.registering(UpdatePackageJson::class) { // description = "Read the package.json file and update the version and name, based on the project." inputs.property("projectVersion", projectVersion) - propertiesToCheck.put("version", projectVersion) +// propertiesToCheck.put("version", projectVersion) + + updateExpectedJson { + put("version", projectVersion.get()) + } // check to see if the properties are already up-to-date // outputs.upToDateWhen(areJsonPropertiesUpToDate(packageJsonFile, propertiesToCheck)) diff --git a/buildSrc/src/main/kotlin/dev/adamko/kafkatorio/task/JsonPropertiesUpToDateSpec.kt b/buildSrc/src/main/kotlin/dev/adamko/kafkatorio/task/JsonPropertiesUpToDateSpec.kt index 30f9ee0..8b61b06 100644 --- a/buildSrc/src/main/kotlin/dev/adamko/kafkatorio/task/JsonPropertiesUpToDateSpec.kt +++ b/buildSrc/src/main/kotlin/dev/adamko/kafkatorio/task/JsonPropertiesUpToDateSpec.kt @@ -1,15 +1,23 @@ package dev.adamko.kafkatorio.task +import dev.adamko.kafkatorio.task.UpdatePackageJson.Companion.foldParseToJsonObject +import dev.adamko.kafkatorio.task.UpdatePackageJson.Companion.parseToJsonObject +import kotlinx.serialization.json.JsonObject import org.gradle.api.Task import org.gradle.api.internal.specs.ExplainingSpec +import org.gradle.api.logging.Logger +import org.gradle.api.logging.Logging + object JsonPropertiesUpToDateSpec : ExplainingSpec { + private val logger: Logger = Logging.getLogger(this::class.java) + override fun isSatisfiedBy(element: Task?): Boolean { val reason = whyUnsatisfied(element) if (reason != null) { - println("JsonProperties not up to date:\n$reason") + logger.lifecycle("JsonProperties not up to date:\n$reason") } return reason == null @@ -21,26 +29,31 @@ object JsonPropertiesUpToDateSpec : ExplainingSpec { override fun whyUnsatisfied(task: Task?): String? { require(task is UpdatePackageJson) { "$task is not a UpdatePackageJson task" } - val current = task.currentPackageJson() - val updated = task.updatedPackageJson(current) + val current = task.packageJsonFile.asFile.orNull?.parseToJsonObject() + ?: return "no package.json file" - return if (current != updated) { - (current.keys + updated.keys) + val updates = task.expectedJsonUpdates.orNull?.toList()?.foldParseToJsonObject() + ?: return "no package.json updates" + + val expected = JsonObject(current + updates) + + if (current != expected) { + return (current.keys + expected.keys) .asSequence() .distinct() .sorted() .mapNotNull { val currentVal = current[it] - val updatedVal = updated[it] + val expectedVal = expected[it] - if (currentVal == updatedVal) { + if (currentVal == expectedVal) { null } else { - "'$it' - expected:$updatedVal, actual:$currentVal" + "'$it' - expected:$expectedVal, actual:$currentVal" } }.joinToString(separator = "\n\t", prefix = "package.json is not up to date.\n\t") - } else { - null } + + return null } } diff --git a/buildSrc/src/main/kotlin/dev/adamko/kafkatorio/task/UpdatePackageJson.kt b/buildSrc/src/main/kotlin/dev/adamko/kafkatorio/task/UpdatePackageJson.kt index ddfa6ce..acae0c3 100644 --- a/buildSrc/src/main/kotlin/dev/adamko/kafkatorio/task/UpdatePackageJson.kt +++ b/buildSrc/src/main/kotlin/dev/adamko/kafkatorio/task/UpdatePackageJson.kt @@ -1,15 +1,19 @@ package dev.adamko.kafkatorio.task import com.github.gradle.node.NodePlugin -import dev.adamko.kafkatorio.jsonMapper +import dev.adamko.kafkatorio.* +import java.io.File import javax.inject.Inject import kotlinx.serialization.encodeToString +import kotlinx.serialization.json.Json import kotlinx.serialization.json.JsonObject -import kotlinx.serialization.json.JsonPrimitive +import kotlinx.serialization.json.JsonObjectBuilder +import kotlinx.serialization.json.buildJsonObject import kotlinx.serialization.json.jsonObject import org.gradle.api.DefaultTask import org.gradle.api.file.RegularFileProperty -import org.gradle.api.provider.MapProperty +import org.gradle.api.provider.ListProperty +import org.gradle.api.provider.Property import org.gradle.api.provider.ProviderFactory import org.gradle.api.tasks.CacheableTask import org.gradle.api.tasks.Input @@ -18,13 +22,19 @@ import org.gradle.api.tasks.TaskAction import org.gradle.kotlin.dsl.support.useToRun import org.jetbrains.kotlin.util.suffixIfNot + @CacheableTask abstract class UpdatePackageJson @Inject constructor( private val providers: ProviderFactory, -) : DefaultTask() { +) : DefaultTask(), + ProviderFactory by providers { +// @get:Input +// abstract val propertiesToCheck: MapProperty + + /** Cumulative updates */ @get:Input - abstract val propertiesToCheck: MapProperty + internal abstract val expectedJsonUpdates: ListProperty @get:OutputFile abstract val packageJsonFile: RegularFileProperty @@ -32,51 +42,93 @@ abstract class UpdatePackageJson @Inject constructor( init { group = NodePlugin.NPM_GROUP - description = - "Read the package.json file and update the version and name, based on the current project." + description = "Update package.json properties" outputs.upToDateWhen(JsonPropertiesUpToDateSpec) + +// expectedJson.convention("{}") } @TaskAction fun exec() { val packageJsonFile = packageJsonFile.asFile.get() + val expectedJsonUpdates: List = expectedJsonUpdates.get().toList() - logger.lifecycle("updating package.json ${packageJsonFile.canonicalPath}") + logger.lifecycle("updating package.json ${packageJsonFile.canonicalFile}") - val updatedPackageJson = updatedPackageJson() + val expectedJson = expectedJsonUpdates.fold(JsonObject(emptyMap())) { acc, update -> + val updateJson = jsonMapper.parseToJsonElement(update).jsonObject + JsonObject(acc + updateJson) + } - val packageJsonContentUpdated = + val updatedPackageJson = JsonObject( + packageJsonFile.parseToJsonObject() + expectedJson + ) + + val packageJsonContentFormatted = jsonMapper .encodeToString(updatedPackageJson) - // change empty arrays/objects, because `npm install` also formats package.json, but - // slightly differently to kxs. - .replace( ": {\n }", ": {}") - .replace( ": [\n ]", ": []") + // change empty arrays/objects, because `npm install` also formats package.json, + // but slightly differently to kxs. + .replace(": {\n }", ": {}") + .replace(": [\n ]", ": []") .suffixIfNot("\n") - logger.debug(packageJsonContentUpdated) + logger.info(packageJsonContentFormatted) packageJsonFile.writer().useToRun { - write(packageJsonContentUpdated) + write(packageJsonContentFormatted) } } - internal fun currentPackageJson(): JsonObject { - val packageJsonFile = packageJsonFile.get().asFile - return jsonMapper.parseToJsonElement(packageJsonFile.readText()).jsonObject + + /** Update [expectedJson] by merging [updateJsonProvider] with the existing value. */ + fun updateExpectedJson( + expectedJsonUpdate: JsonObjectBuilder.() -> Unit + ) { + val expectedJsonUpdateProvider = provider { + buildJsonObject(expectedJsonUpdate).toString() + } + + expectedJsonUpdates.add(expectedJsonUpdateProvider) + +// val newJson = +// expectedJson.zip(expectedJsonUpdateProvider) { currentJsonString, inputJsonString -> +// val currentJson = jsonMapper.encodeToJsonElement(currentJsonString).jsonObject +// +// val inputJson = jsonMapper.encodeToJsonElement(inputJsonString).jsonObject +// +// val newJson = JsonObject(currentJson + inputJson) +// +// jsonMapper.encodeToString(newJson) +// } +// +// expectedJson.set(newJson) } - internal fun updatedPackageJson( - currentPackageJson: JsonObject = currentPackageJson(), - ): JsonObject { - val propertiesToCheck: Map = propertiesToCheck.get() - val newJsonProps = propertiesToCheck.mapValues { (_, newVal) -> - JsonPrimitive(newVal) + + companion object { + private val jsonMapper = Json { + prettyPrint = true + prettyPrintIndent = " " } - return JsonObject(currentPackageJson + newJsonProps) + + + internal fun File.parseToJsonObject(): JsonObject = + jsonMapper.parseToJsonElement(readText()).jsonObject + + + internal fun Property.parseToJsonObject(): JsonObject = + jsonMapper.parseToJsonElement(get()).jsonObject + + + internal fun List.foldParseToJsonObject(): JsonObject = + fold(JsonObject(emptyMap())) { acc, update -> + val updateJson = jsonMapper.parseToJsonElement(update).jsonObject + JsonObject(acc + updateJson) + } } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 5fb90e7..9302dc8 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -45,6 +45,15 @@ kotkaStreams = "dev-SNAPSHOT" marykRocksDb = "7.3.1" # https://search.maven.org/artifact/io.maryk.rocksdb/rocksdb-multiplatform + +## npm ## + +npm-luaTypes = "2.12.0" +npm-typescriptToLua = "1.8.2" +npm-typedFactorio = "1.6.1" +npm-typescript = "4.7.4" + + ## test ## junit = "5.8.2" kotest = "5.3.1" diff --git a/modules/events-mod/build.gradle.kts b/modules/events-mod/build.gradle.kts index 206b8d8..c3398d7 100644 --- a/modules/events-mod/build.gradle.kts +++ b/modules/events-mod/build.gradle.kts @@ -4,6 +4,8 @@ import dev.adamko.kafkatorio.gradle.asProvider import dev.adamko.kafkatorio.gradle.factorioModAttributes import dev.adamko.kafkatorio.gradle.typescriptAttributes import dev.adamko.kafkatorio.task.TypescriptToLuaTask +import kotlinx.serialization.json.put +import kotlinx.serialization.json.putJsonObject import net.swiftzer.semver.SemVer import org.apache.tools.ant.filters.ReplaceTokens import org.gradle.plugins.ide.idea.model.Module as IdeaImlModule @@ -175,15 +177,26 @@ val factorioModProvider by configurations.registering { } -val packageJsonName: Provider = providers.provider { "${rootProject.name}-${project.name}" } -val pjProvider: RegularFileProperty = - objects.fileProperty().convention(layout.projectDirectory.file("package.json")) +val projectPackageJsonName: Provider = + providers.provider { "${rootProject.name}-${project.name}" } +val projectPackageJsonFile: RegularFile = layout.projectDirectory.file("package.json") +val projectVersion: Provider = providers.provider { "${project.version}" } + tasks.updatePackageJson { // mustRunAfter(tasks.npmInstall) - inputs.property("packageJsonName", packageJsonName) - propertiesToCheck.put("name", packageJsonName) - packageJsonFile.set(pjProvider) + + updateExpectedJson { + put("name", projectPackageJsonName.get()) + putJsonObject("dependencies") { + put("lua-types", libs.versions.npm.luaTypes.get()) + put("typescript-to-lua", libs.versions.npm.typescriptToLua.get()) + put("typed-factorio", libs.versions.npm.typedFactorio.get()) + put("typescript", libs.versions.npm.typescript.get()) + } + } + + packageJsonFile.set(projectPackageJsonFile) } diff --git a/modules/events-mod/package-lock.json b/modules/events-mod/package-lock.json index eff221b..ac356aa 100644 --- a/modules/events-mod/package-lock.json +++ b/modules/events-mod/package-lock.json @@ -32,17 +32,17 @@ } }, "is-core-module": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.9.0.tgz", - "integrity": "sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==", + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz", + "integrity": "sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==", "requires": { "has": "^1.0.3" } }, "lua-types": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/lua-types/-/lua-types-2.11.0.tgz", - "integrity": "sha512-J/8qHrOjkZuPBDhnuAg0DWoaJEImqXNzgEnUigCTVrSVCcchM5Y5zpcI3aWAZPhuZlb0QKC/f3nc7VGmZmBg7w==" + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/lua-types/-/lua-types-2.12.0.tgz", + "integrity": "sha512-s96z1Zcz3KRXfWyNFM3KP2zpNYTfZwgHo8X/yFXveyS8Dux+cUuyT+zA5tFZbmGh8VViwNs9bFbzNevAR/18uw==" }, "path-parse": { "version": "1.0.7", @@ -75,9 +75,9 @@ "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==" }, "typed-factorio": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/typed-factorio/-/typed-factorio-1.4.0.tgz", - "integrity": "sha512-hT5YDtdJk/hVIm83hYlXx2vOSmhElQhHhcI0OIrdx2nmrx18zKEnjGk4abJ6WHjuy4xoVZ+00mjnC3mWclvrzw==" + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/typed-factorio/-/typed-factorio-1.6.1.tgz", + "integrity": "sha512-ehxUmRUPO4IEhtXIOkwhosDGGEVgRBFVaoNkTOvko/3yLKwese/6IB1/9ItSRNspqOoNh4UBPscjvQWM3SIFBA==" }, "typescript": { "version": "4.7.4", @@ -85,9 +85,9 @@ "integrity": "sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==" }, "typescript-to-lua": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/typescript-to-lua/-/typescript-to-lua-1.7.1.tgz", - "integrity": "sha512-iDjCnel38p3Cxv+Las8rBzd6BaRIE49DQSyFOgupg4gSw36+8H1xtwde3lRdGMPZx19/zVwXEO8UspiACYJc+A==", + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/typescript-to-lua/-/typescript-to-lua-1.8.2.tgz", + "integrity": "sha512-2ZFJlF9R9HgTryM+Vwk3X3Dexnvpm5vT75Eh66E0rDFZGK+vW70aqkw6s47/ytdJg/9IyN+Oz7ITUzZxXEOxlA==", "requires": { "enhanced-resolve": "^5.8.2", "resolve": "^1.15.1", diff --git a/modules/events-mod/package.json b/modules/events-mod/package.json index d9a4fc4..10ea923 100644 --- a/modules/events-mod/package.json +++ b/modules/events-mod/package.json @@ -11,9 +11,9 @@ }, "devDependencies": {}, "dependencies": { - "lua-types": "^2.11.0", - "typescript-to-lua": "1.7.1", - "typed-factorio": "1.4.0", + "lua-types": "2.12.0", + "typescript-to-lua": "1.8.2", + "typed-factorio": "1.6.1", "typescript": "4.7.4" }, "license": "UNLICENSED",