diff --git a/.gitignore b/.gitignore index 46c1c3b..6544842 100644 --- a/.gitignore +++ b/.gitignore @@ -1,8 +1,7 @@ __pycache__ .DS_Store -kotlin/do-test* -swift/do-test +do-test* local.properties .gradle build -test/test-dir/entities.kt +test-dir/entities.kt diff --git a/CHANELOG.md b/CHANGELOG.md similarity index 88% rename from CHANELOG.md rename to CHANGELOG.md index 7765db0..9b2f350 100644 --- a/CHANELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,10 @@ +# [2.0](https://github.com/OGStudio/kotlin-dialect/pull/13) + +TODO + +1. The project has been renamed to Kotlin Dialect to emphasize.... +1. Version 1.x has been moved to history/2025 + # [1.3.0](https://github.com/OGStudio/cross-language-dialect/pull/12) #### 2026-01-22 diff --git a/history/README.md b/history/2024/README.md similarity index 100% rename from history/README.md rename to history/2024/README.md diff --git a/history/ctx/ctx.py b/history/2024/ctx/ctx.py similarity index 100% rename from history/ctx/ctx.py rename to history/2024/ctx/ctx.py diff --git a/history/ctx/ctx_test_Python.py b/history/2024/ctx/ctx_test_Python.py similarity index 100% rename from history/ctx/ctx_test_Python.py rename to history/2024/ctx/ctx_test_Python.py diff --git a/history/do-translate b/history/2024/do-translate similarity index 100% rename from history/do-translate rename to history/2024/do-translate diff --git a/history/lib/cld.py b/history/2024/lib/cld.py similarity index 100% rename from history/lib/cld.py rename to history/2024/lib/cld.py diff --git a/history/lib/cld_test.py b/history/2024/lib/cld_test.py similarity index 100% rename from history/lib/cld_test.py rename to history/2024/lib/cld_test.py diff --git a/history/lib/cld_test_Python.py b/history/2024/lib/cld_test_Python.py similarity index 100% rename from history/lib/cld_test_Python.py rename to history/2024/lib/cld_test_Python.py diff --git a/history/tr/Context.py b/history/2024/tr/Context.py similarity index 100% rename from history/tr/Context.py rename to history/2024/tr/Context.py diff --git a/history/tr/fs.py b/history/2024/tr/fs.py similarity index 100% rename from history/tr/fs.py rename to history/2024/tr/fs.py diff --git a/history/tr/fs_aux.py b/history/2024/tr/fs_aux.py similarity index 100% rename from history/tr/fs_aux.py rename to history/2024/tr/fs_aux.py diff --git a/history/tr/js.py b/history/2024/tr/js.py similarity index 100% rename from history/tr/js.py rename to history/2024/tr/js.py diff --git a/history/tr/js_aux.py b/history/2024/tr/js_aux.py similarity index 100% rename from history/tr/js_aux.py rename to history/2024/tr/js_aux.py diff --git a/history/tr/js_aux_test.py b/history/2024/tr/js_aux_test.py similarity index 100% rename from history/tr/js_aux_test.py rename to history/2024/tr/js_aux_test.py diff --git a/history/tr/js_test.py b/history/2024/tr/js_test.py similarity index 100% rename from history/tr/js_test.py rename to history/2024/tr/js_test.py diff --git a/README.md b/history/2025/README.md similarity index 100% rename from README.md rename to history/2025/README.md diff --git a/cld/entities.yml b/history/2025/cld/entities.yml similarity index 100% rename from cld/entities.yml rename to history/2025/cld/entities.yml diff --git a/cld/generate-entities b/history/2025/cld/generate-entities similarity index 100% rename from cld/generate-entities rename to history/2025/cld/generate-entities diff --git a/javascript/CLDController.js b/history/2025/javascript/CLDController.js similarity index 100% rename from javascript/CLDController.js rename to history/2025/javascript/CLDController.js diff --git a/javascript/main.js b/history/2025/javascript/main.js similarity index 100% rename from javascript/main.js rename to history/2025/javascript/main.js diff --git a/javascript/test.js b/history/2025/javascript/test.js similarity index 100% rename from javascript/test.js rename to history/2025/javascript/test.js diff --git a/kotlin/CLDContext.kt b/history/2025/kotlin/CLDContext.kt similarity index 100% rename from kotlin/CLDContext.kt rename to history/2025/kotlin/CLDContext.kt diff --git a/kotlin/CLDController.kt b/history/2025/kotlin/CLDController.kt similarity index 100% rename from kotlin/CLDController.kt rename to history/2025/kotlin/CLDController.kt diff --git a/kotlin/main.kt b/history/2025/kotlin/main.kt similarity index 100% rename from kotlin/main.kt rename to history/2025/kotlin/main.kt diff --git a/kotlin/make b/history/2025/kotlin/make similarity index 100% rename from kotlin/make rename to history/2025/kotlin/make diff --git a/kotlin/registerOneliners.kt b/history/2025/kotlin/registerOneliners.kt similarity index 100% rename from kotlin/registerOneliners.kt rename to history/2025/kotlin/registerOneliners.kt diff --git a/kotlin/test.kt b/history/2025/kotlin/test.kt similarity index 100% rename from kotlin/test.kt rename to history/2025/kotlin/test.kt diff --git a/swift/CLDContext.swift b/history/2025/swift/CLDContext.swift similarity index 100% rename from swift/CLDContext.swift rename to history/2025/swift/CLDContext.swift diff --git a/swift/CLDController.swift b/history/2025/swift/CLDController.swift similarity index 100% rename from swift/CLDController.swift rename to history/2025/swift/CLDController.swift diff --git a/swift/main.swift b/history/2025/swift/main.swift similarity index 100% rename from swift/main.swift rename to history/2025/swift/main.swift diff --git a/swift/make b/history/2025/swift/make similarity index 100% rename from swift/make rename to history/2025/swift/make diff --git a/swift/test.swift b/history/2025/swift/test.swift similarity index 100% rename from swift/test.swift rename to history/2025/swift/test.swift diff --git a/history/2025/test/test-dir/entities.kt b/history/2025/test/test-dir/entities.kt new file mode 100644 index 0000000..9c6fd7b --- /dev/null +++ b/history/2025/test/test-dir/entities.kt @@ -0,0 +1,69 @@ +package org.opengamestudio + +// Application state context +data class Context( + // Command line arguments + var arguments: Array = arrayOf(), + var consoleOutput: String = "", + var didLaunch: Boolean = false, + // Dictionary of dictionaries + var entityFieldComments: Map> = mapOf(), + var httpDefaultPort: Int = 0, + var httpRequest: NetRequest = NetRequest(), + override var recentField: String = "", +): CLDContext { + override fun field(name: String): T { + if (name == "arguments") { + return arguments as T + } else if (name == "consoleOutput") { + return consoleOutput as T + } else if (name == "didLaunch") { + return didLaunch as T + } else if (name == "entityFieldComments") { + return entityFieldComments as T + } else if (name == "httpDefaultPort") { + return httpDefaultPort as T + } else if (name == "httpRequest") { + return httpRequest as T + } + return "unknown-field-name" as T + } + + override fun selfCopy(): CLDContext { + return this.copy() + } + + override fun setField( + name: String, + value: Any? + ) { + if (name == "arguments") { + arguments = value as Array + } else if (name == "consoleOutput") { + consoleOutput = value as String + } else if (name == "didLaunch") { + didLaunch = value as Boolean + } else if (name == "entityFieldComments") { + entityFieldComments = value as Map> + } else if (name == "httpDefaultPort") { + httpDefaultPort = value as Int + } else if (name == "httpRequest") { + httpRequest = value as NetRequest + } + } +} + + +data class FSFile( + var isDirectory: Boolean = false, + var isFile: Boolean = false, + var name: String = "", +) {} + +// Network request representation +data class NetRequest( + var body: String = "", + // GET, POST, etc. + var method: String = "", + var path: String = "", +) {} diff --git a/test/test-dir/entities.yml b/history/2025/test/test-dir/entities.yml similarity index 100% rename from test/test-dir/entities.yml rename to history/2025/test/test-dir/entities.yml diff --git a/translator/gradle.properties b/history/2025/translator/gradle.properties similarity index 100% rename from translator/gradle.properties rename to history/2025/translator/gradle.properties diff --git a/translator/gradle/libs.versions.toml b/history/2025/translator/gradle/libs.versions.toml similarity index 100% rename from translator/gradle/libs.versions.toml rename to history/2025/translator/gradle/libs.versions.toml diff --git a/translator/gradle/wrapper/gradle-wrapper.jar b/history/2025/translator/gradle/wrapper/gradle-wrapper.jar similarity index 100% rename from translator/gradle/wrapper/gradle-wrapper.jar rename to history/2025/translator/gradle/wrapper/gradle-wrapper.jar diff --git a/translator/gradle/wrapper/gradle-wrapper.properties b/history/2025/translator/gradle/wrapper/gradle-wrapper.properties similarity index 100% rename from translator/gradle/wrapper/gradle-wrapper.properties rename to history/2025/translator/gradle/wrapper/gradle-wrapper.properties diff --git a/translator/gradlew b/history/2025/translator/gradlew similarity index 100% rename from translator/gradlew rename to history/2025/translator/gradlew diff --git a/translator/gradlew.bat b/history/2025/translator/gradlew.bat similarity index 100% rename from translator/gradlew.bat rename to history/2025/translator/gradlew.bat diff --git a/translator/jvm/build.gradle.kts b/history/2025/translator/jvm/build.gradle.kts similarity index 100% rename from translator/jvm/build.gradle.kts rename to history/2025/translator/jvm/build.gradle.kts diff --git a/translator/jvm/src/main/kotlin/org/opengamestudio/CLDContext.kt b/history/2025/translator/jvm/src/main/kotlin/org/opengamestudio/CLDContext.kt similarity index 100% rename from translator/jvm/src/main/kotlin/org/opengamestudio/CLDContext.kt rename to history/2025/translator/jvm/src/main/kotlin/org/opengamestudio/CLDContext.kt diff --git a/translator/jvm/src/main/kotlin/org/opengamestudio/CLDController.kt b/history/2025/translator/jvm/src/main/kotlin/org/opengamestudio/CLDController.kt similarity index 100% rename from translator/jvm/src/main/kotlin/org/opengamestudio/CLDController.kt rename to history/2025/translator/jvm/src/main/kotlin/org/opengamestudio/CLDController.kt diff --git a/translator/jvm/src/main/kotlin/org/opengamestudio/JVMApp.kt b/history/2025/translator/jvm/src/main/kotlin/org/opengamestudio/JVMApp.kt similarity index 100% rename from translator/jvm/src/main/kotlin/org/opengamestudio/JVMApp.kt rename to history/2025/translator/jvm/src/main/kotlin/org/opengamestudio/JVMApp.kt diff --git a/translator/jvm/src/main/kotlin/org/opengamestudio/console.kt b/history/2025/translator/jvm/src/main/kotlin/org/opengamestudio/console.kt similarity index 100% rename from translator/jvm/src/main/kotlin/org/opengamestudio/console.kt rename to history/2025/translator/jvm/src/main/kotlin/org/opengamestudio/console.kt diff --git a/translator/jvm/src/main/kotlin/org/opengamestudio/constants.kt b/history/2025/translator/jvm/src/main/kotlin/org/opengamestudio/constants.kt similarity index 100% rename from translator/jvm/src/main/kotlin/org/opengamestudio/constants.kt rename to history/2025/translator/jvm/src/main/kotlin/org/opengamestudio/constants.kt diff --git a/translator/jvm/src/main/kotlin/org/opengamestudio/entities.kt b/history/2025/translator/jvm/src/main/kotlin/org/opengamestudio/entities.kt similarity index 100% rename from translator/jvm/src/main/kotlin/org/opengamestudio/entities.kt rename to history/2025/translator/jvm/src/main/kotlin/org/opengamestudio/entities.kt diff --git a/translator/jvm/src/main/kotlin/org/opengamestudio/fs_jvm.kt b/history/2025/translator/jvm/src/main/kotlin/org/opengamestudio/fs_jvm.kt similarity index 100% rename from translator/jvm/src/main/kotlin/org/opengamestudio/fs_jvm.kt rename to history/2025/translator/jvm/src/main/kotlin/org/opengamestudio/fs_jvm.kt diff --git a/translator/jvm/src/main/kotlin/org/opengamestudio/genKotlin.kt b/history/2025/translator/jvm/src/main/kotlin/org/opengamestudio/genKotlin.kt similarity index 100% rename from translator/jvm/src/main/kotlin/org/opengamestudio/genKotlin.kt rename to history/2025/translator/jvm/src/main/kotlin/org/opengamestudio/genKotlin.kt diff --git a/translator/jvm/src/main/kotlin/org/opengamestudio/other.kt b/history/2025/translator/jvm/src/main/kotlin/org/opengamestudio/other.kt similarity index 100% rename from translator/jvm/src/main/kotlin/org/opengamestudio/other.kt rename to history/2025/translator/jvm/src/main/kotlin/org/opengamestudio/other.kt diff --git a/translator/jvm/src/main/kotlin/org/opengamestudio/parseEntity.kt b/history/2025/translator/jvm/src/main/kotlin/org/opengamestudio/parseEntity.kt similarity index 100% rename from translator/jvm/src/main/kotlin/org/opengamestudio/parseEntity.kt rename to history/2025/translator/jvm/src/main/kotlin/org/opengamestudio/parseEntity.kt diff --git a/translator/jvm/src/main/kotlin/org/opengamestudio/shoulds.kt b/history/2025/translator/jvm/src/main/kotlin/org/opengamestudio/shoulds.kt similarity index 100% rename from translator/jvm/src/main/kotlin/org/opengamestudio/shoulds.kt rename to history/2025/translator/jvm/src/main/kotlin/org/opengamestudio/shoulds.kt diff --git a/translator/jvm/src/main/kotlin/org/opengamestudio/templates.kt b/history/2025/translator/jvm/src/main/kotlin/org/opengamestudio/templates.kt similarity index 100% rename from translator/jvm/src/main/kotlin/org/opengamestudio/templates.kt rename to history/2025/translator/jvm/src/main/kotlin/org/opengamestudio/templates.kt diff --git a/translator/run/re-java b/history/2025/translator/run/re-java similarity index 100% rename from translator/run/re-java rename to history/2025/translator/run/re-java diff --git a/translator/run/run-java b/history/2025/translator/run/run-java similarity index 100% rename from translator/run/run-java rename to history/2025/translator/run/run-java diff --git a/translator/settings.gradle.kts b/history/2025/translator/settings.gradle.kts similarity index 100% rename from translator/settings.gradle.kts rename to history/2025/translator/settings.gradle.kts diff --git a/translator/src/CLDContext.kt b/history/2025/translator/src/CLDContext.kt similarity index 100% rename from translator/src/CLDContext.kt rename to history/2025/translator/src/CLDContext.kt diff --git a/translator/src/CLDController.kt b/history/2025/translator/src/CLDController.kt similarity index 100% rename from translator/src/CLDController.kt rename to history/2025/translator/src/CLDController.kt diff --git a/translator/src/console.kt b/history/2025/translator/src/console.kt similarity index 100% rename from translator/src/console.kt rename to history/2025/translator/src/console.kt diff --git a/translator/src/constants.kt b/history/2025/translator/src/constants.kt similarity index 100% rename from translator/src/constants.kt rename to history/2025/translator/src/constants.kt diff --git a/translator/src/entities.kt b/history/2025/translator/src/entities.kt similarity index 100% rename from translator/src/entities.kt rename to history/2025/translator/src/entities.kt diff --git a/translator/src/fs_jvm.kt b/history/2025/translator/src/fs_jvm.kt similarity index 100% rename from translator/src/fs_jvm.kt rename to history/2025/translator/src/fs_jvm.kt diff --git a/translator/src/genKotlin.kt b/history/2025/translator/src/genKotlin.kt similarity index 100% rename from translator/src/genKotlin.kt rename to history/2025/translator/src/genKotlin.kt diff --git a/translator/src/other.kt b/history/2025/translator/src/other.kt similarity index 100% rename from translator/src/other.kt rename to history/2025/translator/src/other.kt diff --git a/translator/src/parseEntity.kt b/history/2025/translator/src/parseEntity.kt similarity index 100% rename from translator/src/parseEntity.kt rename to history/2025/translator/src/parseEntity.kt diff --git a/translator/src/shoulds.kt b/history/2025/translator/src/shoulds.kt similarity index 100% rename from translator/src/shoulds.kt rename to history/2025/translator/src/shoulds.kt diff --git a/translator/src/templates.kt b/history/2025/translator/src/templates.kt similarity index 100% rename from translator/src/templates.kt rename to history/2025/translator/src/templates.kt diff --git a/history/ctx/do-test.py b/history/ctx/do-test.py deleted file mode 100755 index fdf8c9e..0000000 --- a/history/ctx/do-test.py +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env python3 - -import os -import sys - -DIR = os.path.dirname(os.path.realpath(sys.argv[0])) - -sys.path.append(f"{DIR}/../lib") - -from ctx_test_Python import * - -functions = [ - test_ctx_Controller_executeFunctions_registerFunction_set, - test_ctx_Controller_processQueue, - test_ctx_Controller_registerFieldCallback_match, - test_ctx_Controller_registerFieldCallback_mismatch, - test_sample_Context_field, - test_sample_Context_setField -] - -for f in functions: - print(f()) - diff --git a/history/lib/do-test.py b/history/lib/do-test.py deleted file mode 100755 index c4e5ec2..0000000 --- a/history/lib/do-test.py +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/env python3 - -from cld_test import * -from cld_test_Python import * - -functions = [ - test_cld_isdigit_digit, - test_cld_isdigit_notDigit, - test_cld_find, - test_cld_len, - test_cld_lstrip, - test_cld_replace, - test_cld_split, - test_cld_startswith, - test_cld_strtoint, - test_Python_cld_by_value, -] - -for f in functions: - print(f()) diff --git a/history/tr/do-test.py b/history/tr/do-test.py deleted file mode 100755 index 0bf5f55..0000000 --- a/history/tr/do-test.py +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env python3 - -import os -import sys - -SCRIPT_DIR = os.path.dirname(os.path.realpath(sys.argv[0])) -sys.path.append(f"{SCRIPT_DIR}/../lib") - -from js_aux_test import * -from js_test import * - -functions = [ - test_js_aux_conversions, - test_js_aux_copy, - test_js_aux_removeImports, - test_js_aux_replaceComments, - test_js_copy, - test_js_prepareConversions, - test_js_removeImports, - test_js_replaceComments, -] - -for f in functions: - print(f()) diff --git a/javascript/do-test.html b/javascript/do-test.html deleted file mode 100644 index 0b0646d..0000000 --- a/javascript/do-test.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - Test cross-language dialect - - -

- - - - - diff --git a/klin.yml b/klin.yml new file mode 100644 index 0000000..d258d74 --- /dev/null +++ b/klin.yml @@ -0,0 +1,30 @@ +version: 1 + +kotlin: package org.opengamestudio + +AppContext: + type: context + fields: + # Command line arguments + arguments: [String] + consoleOutput: String + didLaunch: Bool + # Entity comments with entities referenced by index + entityComments: [Int: String] + # Entity id -> Field name -> Field comment + entityFieldComments: [Int: [String: String]] + # Entity id -> Field name -> Field type + entityFields: [Int: [String: String]] + # Entity names in the order of appearance + entityNames: [String] + entityPrefixesKotlin: [Int: String] + entityTypes: [Int: String] + didWriteOutputFile: Bool + inputFile: String + inputFileLines: [String] + isDbg: Bool + outputFile: String + # Contents to write to output file + outputFileContents: String + # Kotlin source code to insert as is at the beginning of each generated file + rawKotlin: String diff --git a/klin/ver-nodejs/app/build.gradle.kts b/klin/ver-nodejs/app/build.gradle.kts new file mode 100644 index 0000000..193b400 --- /dev/null +++ b/klin/ver-nodejs/app/build.gradle.kts @@ -0,0 +1,22 @@ +plugins { + alias(libs.plugins.kotlin.multiplatform) +} + +kotlin { + js { + nodejs { } + binaries.executable() + } + + sourceSets { + all { + languageSettings { + optIn("kotlin.js.ExperimentalJsExport") + } + } + } +} + +tasks.withType { + distributionType = Wrapper.DistributionType.BIN +} diff --git a/klin/ver-nodejs/app/src/commonMain/kotlin/org/opengamestudio/KDContext.kt b/klin/ver-nodejs/app/src/commonMain/kotlin/org/opengamestudio/KDContext.kt new file mode 120000 index 0000000..cf652ce --- /dev/null +++ b/klin/ver-nodejs/app/src/commonMain/kotlin/org/opengamestudio/KDContext.kt @@ -0,0 +1 @@ +../../../../../../../../src/KDContext.kt \ No newline at end of file diff --git a/klin/ver-nodejs/app/src/commonMain/kotlin/org/opengamestudio/KDController.kt b/klin/ver-nodejs/app/src/commonMain/kotlin/org/opengamestudio/KDController.kt new file mode 120000 index 0000000..585626d --- /dev/null +++ b/klin/ver-nodejs/app/src/commonMain/kotlin/org/opengamestudio/KDController.kt @@ -0,0 +1 @@ +../../../../../../../../src/KDController.kt \ No newline at end of file diff --git a/klin/ver-nodejs/app/src/commonMain/kotlin/org/opengamestudio/appFun.kt b/klin/ver-nodejs/app/src/commonMain/kotlin/org/opengamestudio/appFun.kt new file mode 100644 index 0000000..1557024 --- /dev/null +++ b/klin/ver-nodejs/app/src/commonMain/kotlin/org/opengamestudio/appFun.kt @@ -0,0 +1,261 @@ +/** + * This file is a part of Kotlin dialect: + * https://github.com/OGStudio/kotlin-dialect + * License: CC0 + * Version: 2.0.0 + */ + +package org.opengamestudio + +import kotlin.js.JsExport + +// + +// Collect comments of the entities +// +// Conditions: +// 1. Entity names are available +fun appShouldCollectEntityComments(c: AppContext): AppContext { + if (c.recentField == "entityNames") { + c.entityComments = parseEntityComments(c.inputFileLines) + c.recentField = "entityComments" + return c + } + + c.recentField = "none" + return c +} + +// Collect field comments +// +// Conditions: +// 1. Entity fields are available +fun appShouldCollectEntityFieldComments(c: AppContext): AppContext { + if (c.recentField == "entityFields") { + c.entityFieldComments = parseEntityFieldComments(c.inputFileLines) + c.recentField = "entityFieldComments" + return c + } + + c.recentField = "none" + return c +} + +// Collect field names and values of the entities +// +// Conditions: +// 1. Entity types are available +fun appShouldCollectEntityFields(c: AppContext): AppContext { + if (c.recentField == "entityTypes") { + c.entityFields = parseEntityFields(c.inputFileLines) + c.recentField = "entityFields" + return c + } + + c.recentField = "none" + return c +} + +// Collect names of the declared entities +// +// Conditions: +// 1. Input file contents are available +fun appShouldCollectEntityNames(c: AppContext): AppContext { + if (c.recentField == "inputFileLines") { + c.entityNames = parseEntityNames(c.inputFileLines) + c.recentField = "entityNames" + return c + } + + c.recentField = "none" + return c +} + +// Collect prefixes of the entities for Kotlin +// +// Conditions: +// 1. Entity comments are available +fun appShouldCollectEntityPrefixesKotlin(c: AppContext): AppContext { + if (c.recentField == "entityComments") { + c.entityPrefixesKotlin = + parseEntityPrefixes( + c.inputFileLines, + PREFIX_PREFIX_KOTLIN + ) + c.recentField = "entityPrefixesKotlin" + return c + } + + c.recentField = "none" + return c +} + +// Collect types of the entities +// +// Conditions: +// 1. Entity comments are available +fun appShouldCollectEntityTypes(c: AppContext): AppContext { + if (c.recentField == "entityComments") { + c.entityTypes = parseEntityTypes(c.inputFileLines) + c.recentField = "entityTypes" + return c + } + + c.recentField = "none" + return c +} + +// Collect raw Kotlin source code +// +// Conditions: +// 1. Input file contents are available +fun appShouldCollectRawKotlin(c: AppContext): AppContext { + if (c.recentField == "inputFileLines") { + c.rawKotlin = parseRawKotlin(c.inputFileLines) + c.recentField = "rawKotlin" + return c + } + + c.recentField = "none" + return c +} + +// Generate Kotlin version of the entities +// +// Conditions: +// 1. Entity field comments are available +fun appShouldGenerateKotlinEntities(c: AppContext): AppContext { + if (c.recentField == "entityFieldComments") { + c.outputFileContents = genKotlinEntitiesFile( + c.entityComments, + c.entityFieldComments, + c.entityFields, + c.entityNames, + c.entityPrefixesKotlin, + c.entityTypes, + c.rawKotlin + ) + c.recentField = "outputFileContents" + return c + } + + c.recentField = "none" + return c +} + +// Parse input file path +// +// Conditions: +// 1. At app launch input file was specified with command line argument +fun appShouldParseInputFilePath(c: AppContext): AppContext { + if ( + c.recentField == "didLaunch" && + cliArgumentValue(c.arguments, ARGUMENT_FILE).length > 0 + ) { + c.inputFile = cliArgumentValue(c.arguments, ARGUMENT_FILE) + c.recentField = "inputFile" + return c + } + + c.recentField = "none" + return c +} + +// Parse output file path +// +// Conditions: +// 1. At app launch output file was specified with command line argument +fun appShouldParseOutputFilePath(c: AppContext): AppContext { + if ( + c.recentField == "didLaunch" && + cliArgumentValue(c.arguments, ARGUMENT_OUT).length > 0 + ) { + c.outputFile = cliArgumentValue(c.arguments, ARGUMENT_OUT) + c.recentField = "outputFile" + return c + } + + c.recentField = "none" + return c +} + +// Print to console +// +// Conditions: +// 1. At app launch no command line arguments were provided +// 2. Line is parsed +fun appShouldPrintToConsole(c: AppContext): AppContext { + if ( + c.recentField == "didLaunch" && + c.arguments.isEmpty() + ) { + c.consoleOutput = "Usage: {bin} --file=/path/to/file.yml --out=/path/to/file.kt" + c.recentField = "consoleOutput" + return c + } + + c.recentField = "none" + return c +} + +/////////////// TODO Convert to effect +// Read input file +// +// Conditions: +// 1. Input file path is available +/* +fun appShouldReadInputFile(c: AppContext): AppContext { + if (c.recentField == "inputFile") { + c.inputFileLines = fsReadFile(c.inputFile) + c.recentField = "inputFileLines" + return c + } + + c.recentField = "none" + return c +} +*/ + +// Reset debug output state +// +// Conditions: +// 1. Arguments are available +fun appShouldResetDbg(c: AppContext): AppContext { + if ( + c.recentField == "arguments" && + cliHasArgument(c.arguments, ARGUMENT_DBG) + ) { + c.isDbg = cliHasArgument(c.arguments, ARGUMENT_DBG) + c.recentField = "isDbg" + return c + } + + c.recentField = "none" + return c +} + +///////// Convert to effect +// Save generated contents to output file +// +// Conditions: +// 1. Finished preparing file contents +/* +fun appShouldWriteOutputFile(c: AppContext): AppContext { + if (c.recentField == "outputFileContents") { + fsWriteFile(c.outputFile, c.outputFileContents) + c.didWriteOutputFile = true + c.recentField = "didWriteOutputFile" + return c + } + + c.recentField = "none" + return c +} +*/ + +// + +@JsExport +fun appCtrl(): KDController { + return AppProto.ctrl +} diff --git a/klin/ver-nodejs/app/src/commonMain/kotlin/org/opengamestudio/appProto.kt b/klin/ver-nodejs/app/src/commonMain/kotlin/org/opengamestudio/appProto.kt new file mode 100644 index 0000000..823bc11 --- /dev/null +++ b/klin/ver-nodejs/app/src/commonMain/kotlin/org/opengamestudio/appProto.kt @@ -0,0 +1,35 @@ +/** + * This file is a part of Kotlin dialect: + * https://github.com/OGStudio/kotlin-dialect + * License: CC0 + * Version: 2.0.0 + */ + +package org.opengamestudio + +object AppProto { + val ctrl: KDController + + init { + ctrl = KDController(AppContext()) + setupComponentDebugging(ctrl, "App") + arrayOf( + ::appShouldCollectEntityComments, + ::appShouldCollectEntityFieldComments, + ::appShouldCollectEntityFields, + ::appShouldCollectEntityNames, + ::appShouldCollectEntityPrefixesKotlin, + ::appShouldCollectEntityTypes, + ::appShouldCollectRawKotlin, + ::appShouldGenerateKotlinEntities, + ::appShouldParseInputFilePath, + ::appShouldPrintToConsole, + ::appShouldParseOutputFilePath, + //::appShouldReadInputFile, + ::appShouldResetDbg, + //::appShouldWriteOutputFile, + ).forEach { f -> + ctrl.registerFunction { c -> f(c as AppContext) } + } + } +} diff --git a/klin/ver-nodejs/app/src/commonMain/kotlin/org/opengamestudio/const.kt b/klin/ver-nodejs/app/src/commonMain/kotlin/org/opengamestudio/const.kt new file mode 100644 index 0000000..628a350 --- /dev/null +++ b/klin/ver-nodejs/app/src/commonMain/kotlin/org/opengamestudio/const.kt @@ -0,0 +1,35 @@ +/** + * This file is a part of Kotlin dialect: + * https://github.com/OGStudio/kotlin-dialect + * License: CC0 + * Version: 2.0.0 + */ + +package org.opengamestudio + +const val ARGUMENT_DBG = "--dbg" +const val ARGUMENT_FILE = "--file" +const val ARGUMENT_OUT = "--out" +const val DBG_LEN = 50 +const val DICTIONARY_DELIMITER = ": " +const val FIELD_DELIMITER = ": " +const val FILE_EXTENSION_JAVASCRIPT = "js" +const val FILE_EXTENSION_KOTLIN = "kt" +const val FILE_EXTENSION_SWIFT = "swift" +const val LANGUAGE_JAVASCRIPT = "JavaScript" +const val LANGUAGE_KOTLIN = "Kotlin" +const val LANGUAGE_SWIFT = "Swift" +const val NEWLINE = "\n" +const val POSTFIX_ENTITY = ":" +const val PREFIX_ENTITY_COMMENT = "# " +const val PREFIX_FIELD = " " +const val PREFIX_FIELD_COMMENT = " # " +const val PREFIX_KOTLIN_ENTITY_COMMENT = "// " +const val PREFIX_KOTLIN_FIELD_COMMENT = " // " +const val PREFIX_PREFIX_KOTLIN = " prefix-kotlin: " +const val PREFIX_RAW_JAVASCRIPT = "javascript: " +const val PREFIX_RAW_KOTLIN = "kotlin: " +const val PREFIX_RAW_SWIFT = "swift: " +const val PREFIX_TYPE = " type: " +const val SECTION_FIELDS = " fields:" +const val TYPE_CONTEXT = "context" diff --git a/klin/ver-nodejs/app/src/commonMain/kotlin/org/opengamestudio/entities.kt b/klin/ver-nodejs/app/src/commonMain/kotlin/org/opengamestudio/entities.kt new file mode 100644 index 0000000..6c59d6a --- /dev/null +++ b/klin/ver-nodejs/app/src/commonMain/kotlin/org/opengamestudio/entities.kt @@ -0,0 +1,109 @@ +package org.opengamestudio + + +data class AppContext( + // Command line arguments + var arguments: Array = arrayOf(), + var consoleOutput: String = "", + var didLaunch: Boolean = false, + var didWriteOutputFile: Boolean = false, + // Entity comments with entities referenced by index + var entityComments: Map = mapOf(), + // Entity id -> Field name -> Field comment + var entityFieldComments: Map> = mapOf(), + // Entity id -> Field name -> Field type + var entityFields: Map> = mapOf(), + // Entity names in the order of appearance + var entityNames: Array = arrayOf(), + var entityPrefixesKotlin: Map = mapOf(), + var entityTypes: Map = mapOf(), + var inputFile: String = "", + var inputFileLines: Array = arrayOf(), + var isDbg: Boolean = false, + var outputFile: String = "", + // Contents to write to output file + var outputFileContents: String = "", + // Kotlin source code to insert as is at the beginning of each generated file + var rawKotlin: String = "", + override var recentField: String = "", +): KDContext { + override fun field(name: String): T { + if (name == "arguments") { + return arguments as T + } else if (name == "consoleOutput") { + return consoleOutput as T + } else if (name == "didLaunch") { + return didLaunch as T + } else if (name == "didWriteOutputFile") { + return didWriteOutputFile as T + } else if (name == "entityComments") { + return entityComments as T + } else if (name == "entityFieldComments") { + return entityFieldComments as T + } else if (name == "entityFields") { + return entityFields as T + } else if (name == "entityNames") { + return entityNames as T + } else if (name == "entityPrefixesKotlin") { + return entityPrefixesKotlin as T + } else if (name == "entityTypes") { + return entityTypes as T + } else if (name == "inputFile") { + return inputFile as T + } else if (name == "inputFileLines") { + return inputFileLines as T + } else if (name == "isDbg") { + return isDbg as T + } else if (name == "outputFile") { + return outputFile as T + } else if (name == "outputFileContents") { + return outputFileContents as T + } else if (name == "rawKotlin") { + return rawKotlin as T + } + return "unknown-field-name" as T + } + + override fun selfCopy(): KDContext { + return this.copy() + } + + override fun setField( + name: String, + value: Any? + ) { + if (name == "arguments") { + arguments = value as Array + } else if (name == "consoleOutput") { + consoleOutput = value as String + } else if (name == "didLaunch") { + didLaunch = value as Boolean + } else if (name == "didWriteOutputFile") { + didWriteOutputFile = value as Boolean + } else if (name == "entityComments") { + entityComments = value as Map + } else if (name == "entityFieldComments") { + entityFieldComments = value as Map> + } else if (name == "entityFields") { + entityFields = value as Map> + } else if (name == "entityNames") { + entityNames = value as Array + } else if (name == "entityPrefixesKotlin") { + entityPrefixesKotlin = value as Map + } else if (name == "entityTypes") { + entityTypes = value as Map + } else if (name == "inputFile") { + inputFile = value as String + } else if (name == "inputFileLines") { + inputFileLines = value as Array + } else if (name == "isDbg") { + isDbg = value as Boolean + } else if (name == "outputFile") { + outputFile = value as String + } else if (name == "outputFileContents") { + outputFileContents = value as String + } else if (name == "rawKotlin") { + rawKotlin = value as String + } + } +} diff --git a/klin/ver-nodejs/app/src/commonMain/kotlin/org/opengamestudio/genKotlin.kt b/klin/ver-nodejs/app/src/commonMain/kotlin/org/opengamestudio/genKotlin.kt new file mode 100644 index 0000000..1d7d1d0 --- /dev/null +++ b/klin/ver-nodejs/app/src/commonMain/kotlin/org/opengamestudio/genKotlin.kt @@ -0,0 +1,254 @@ +/** + * This file is a part of Kotlin dialect: + * https://github.com/OGStudio/kotlin-dialect + * License: CC0 + * Version: 2.0.0 + */ + +package org.opengamestudio + +// Generate Kotlin comment based on its emptiness +fun genKotlinComment(comment: String): String { + if (!comment.isEmpty()) { + return PREFIX_KOTLIN_ENTITY_COMMENT + comment + } + return "" +} + +// Generate Kotlin representation of all YAML entities in a single file +fun genKotlinEntitiesFile( + entityComments: Map, + entityFieldComments: Map>, + entityFields: Map>, + entityNames: Array, + entityPrefixes: Map, + entityTypes: Map, + rawKotlin: String +): String { + var s = rawKotlin + // Entity by id. + var id = 0 + for (name in entityNames) { + val comment = entityComments[id] ?: "" + val prefix = entityPrefixes[id] ?: "" + val type = entityTypes[id] ?: "" + val fieldComments = entityFieldComments[id] ?: mapOf() + val fields = entityFields[id] ?: mapOf() + s += genKotlinEntity(comment, fieldComments, fields, name, prefix, type) + id++ + } + + return s +} + +// Generate Kotlin representation of a single entity +fun genKotlinEntity( + comment: String, + fieldComments: Map, + fields: Map, + name: String, + prefix: String, + type: String +): String { + // Use `struct` template by default + var template = TEMPLATE_KOTLIN_STRUCT + if (type == TYPE_CONTEXT) { + template = TEMPLATE_KOTLIN_CONTEXT + } + + val genComment = genKotlinComment(comment) + val genFields = genKotlinFields(fieldComments, fields) + val genGetters = genKotlinGetters(fields) + val genSetters = genKotlinSetters(fields) + return template + .replace("%NAME%", name) + .replace("%COMMENT%", genComment) + .replace("%FIELDS%", genFields) + .replace("%GETTERS%", genGetters) + .replace("%PREFIX%", prefix) + .replace("%SETTERS%", genSetters) +} + +// Generate Kotlin field and its comment +fun genKotlinField( + comment: String, + name: String, + ymlType: String +): String { + var contents = "" + if (!comment.isEmpty()) { + contents += PREFIX_KOTLIN_FIELD_COMMENT + comment + NEWLINE + } + val default = genKotlinFieldDefault(ymlType) + val type = genKotlinFieldType(ymlType) + contents += TEMPLATE_KOTLIN_FIELD + .replace("%NAME%", name) + .replace("%TYPE%", type) + .replace("%DEFAULT%", default) + return contents +} + +// Construct type's default value string +fun genKotlinFieldDefault(type: String): String { + // `Bool` -> `false` + if (type == "Bool") { + return "false" + } + // `Double` -> `0` + if (type == "Double") { + return "0" + } + // `Int` -> `0` + if (type == "Int") { + return "0" + } + // `Long` -> `0` + if (type == "Long") { + return "0" + } + // `String` -> `""` + if (type == "String") { + return "\"\"" + } + // `[Type]` -> `arrayOf()` + if ( + type.startsWith("[") && + type.endsWith("]") && + !type.contains(DICTIONARY_DELIMITER) + ) { + return "arrayOf()" + } + // `[TypeA: TypeB]` -> `mapOf()` + if ( + type.startsWith("[") && + type.endsWith("]") && + type.contains(DICTIONARY_DELIMITER) + ) { + return "mapOf()" + } + + // `AnyOtherType` -> `AnyOtherType()` + return "$type()" +} + +// Generate Kotlin fields and their comments +fun genKotlinFields( + fieldComments: Map, + fields: Map +): String { + var contents = "" + val sortedFieldNames = fields.keys.sorted() + for (name in sortedFieldNames) { + // Add new line among fields + if (!contents.isEmpty()) { + contents += NEWLINE + } + val comment: String = fieldComments[name] ?: "" + val type = fields[name] ?: "" + contents += genKotlinField(comment, name, type) + } + return contents +} + +// Construct type string +fun genKotlinFieldType(type: String): String { + // `Bool` -> `Boolean` + if (type == "Bool") { + return "Boolean" + } + // `Double` -> `Double` + if (type == "Double") { + return "Double" + } + // `Long` -> `Long` + if (type == "Long") { + return "Long" + } + // `[Type]` -> `Array` + if ( + type.startsWith("[") && + type.endsWith("]") && + !type.contains(DICTIONARY_DELIMITER) // Exclude dictionary + ) { + val innerString = type.substring(1, type.length - 1) + // Recursive call to format inner string + val innerType = genKotlinFieldType(innerString) + return "Array<$innerType>" + } + // `[TypeA: TypeB]` -> `Map` + if ( + type.startsWith("[") && + type.endsWith("]") && + type.contains(DICTIONARY_DELIMITER) + ) { + val innerString = type.substring(1, type.length - 1) + val parts = innerString.split(DICTIONARY_DELIMITER, limit = 2) + // Recursive calls to format types + val innerTypeA = genKotlinFieldType(parts.first()) + val innerTypeB = genKotlinFieldType(parts.last()) + return "Map<$innerTypeA, $innerTypeB>" + } + + // Return everything else as is + return type +} + +// Generate Kotlin Context getter +fun genKotlinGetter( + isFirst: Boolean, + name: String +): String { + // Use `GETTER` template by default + var template = TEMPLATE_KOTLIN_CONTEXT_GETTER + if (isFirst) { + template = TEMPLATE_KOTLIN_CONTEXT_GETTER_FIRST + } + var contents = "" + contents += template + .replace("%NAME%", name) + return contents +} + +// Generate Kotlin Context getters +fun genKotlinGetters(fields: Map): String { + var contents = "" + var isFirst = true + val sortedFieldNames = fields.keys.sorted() + for (name in sortedFieldNames) { + contents += genKotlinGetter(isFirst, name) + isFirst = false + } + return contents +} + +// Generate Kotlin Context setter +fun genKotlinSetter( + isFirst: Boolean, + name: String, + ymlType: String +): String { + // Use `SETTER` template by default + var template = TEMPLATE_KOTLIN_CONTEXT_SETTER + if (isFirst) { + template = TEMPLATE_KOTLIN_CONTEXT_SETTER_FIRST + } + var contents = "" + val type = genKotlinFieldType(ymlType) + contents += template + .replace("%NAME%", name) + .replace("%TYPE%", type) + return contents +} + +// Generate Kotlin Context setters +fun genKotlinSetters(fields: Map): String { + var contents = "" + var isFirst = true + val sortedFieldNames = fields.keys.sorted() + for (name in sortedFieldNames) { + val type = fields[name] ?: "" + contents += genKotlinSetter(isFirst, name, type) + isFirst = false + } + return contents +} diff --git a/klin/ver-nodejs/app/src/commonMain/kotlin/org/opengamestudio/other.kt b/klin/ver-nodejs/app/src/commonMain/kotlin/org/opengamestudio/other.kt new file mode 100644 index 0000000..8965c8a --- /dev/null +++ b/klin/ver-nodejs/app/src/commonMain/kotlin/org/opengamestudio/other.kt @@ -0,0 +1,96 @@ +/** + * This file is a part of Kotlin dialect: + * https://github.com/OGStudio/kotlin-dialect + * License: CC0 + * Version: 2.0.0 + */ + +package org.opengamestudio + +// Extract command line argument value +fun cliArgumentValue( + args: Array, + argument: String +): String { + for (item in args) { + if (item.startsWith(argument)) { + val prefix = argument + "=" + val value = item.substring(prefix.length) + return value + } + } + return "" +} + +// Detect command line argument presence +fun cliHasArgument( + args: Array, + argument: String +): Boolean { + for (arg in args) { + if (arg == argument) { + return true + } + } + return false +} + +// Debug representation of a value +fun debugString(v: Any): String { + // Prepend a string with its length + if (v is String) { + return "S(${v.length})$v" + } + + // Prepend an array with its size + if (v is Array<*>) { + var out = "" + for (item in v) { + if (!out.isEmpty()) { + out += "," + } + out += debugString(item!!) + } + return "A(${v.size})$out" + } + + // Prepend a dictionary with its size + if (v is Map<*, *>) { + var out = "" + for ((key, value) in v) { + if (!out.isEmpty()) { + out += "," + } + out += debugString(key!!) + ":" + debugString(value!!) + } + return "D(${v.size})$out" + } + + // For other types return whatever Kotlin returns by default + return "$v" +} + +// Collect raw Kotlin source code +fun parseRawKotlin(lines: Array): String { + var contents = "" + for (ln in lines) { + if (ln.startsWith(PREFIX_RAW_KOTLIN)) { + val prefixLen = PREFIX_RAW_KOTLIN.length + val kotlinCode = ln.substring(prefixLen) + contents += kotlinCode + NEWLINE + } + } + + return contents +} + +fun setupComponentDebugging( + ctrl: KDController, + prefix: String +) { + ctrl.registerCallback { c -> + //val value = "${c.field(c.recentField)}" + val value = debugString(c.fieldAny(c.recentField)) + println("ИГР $prefix k/v: '${c.recentField}'/'$value'") + } +} diff --git a/klin/ver-nodejs/app/src/commonMain/kotlin/org/opengamestudio/parseEntity.kt b/klin/ver-nodejs/app/src/commonMain/kotlin/org/opengamestudio/parseEntity.kt new file mode 100644 index 0000000..fde2baa --- /dev/null +++ b/klin/ver-nodejs/app/src/commonMain/kotlin/org/opengamestudio/parseEntity.kt @@ -0,0 +1,191 @@ +/** + * This file is a part of Kotlin dialect: + * https://github.com/OGStudio/kotlin-dialect + * License: CC0 + * Version: 2.0.0 + */ + +package org.opengamestudio + +// Collect comments of entities +fun parseEntityComments(lines: Array): Map { + var d = mutableMapOf() + var entityId = 0 + for (ln in lines) { + if (ln.startsWith(PREFIX_ENTITY_COMMENT)) { + val prefixLen = PREFIX_ENTITY_COMMENT.length + val comment = ln.substring(prefixLen) + d[entityId] = comment + } else if (!parseEntityName(ln).isEmpty()) { + // Increase id only when entity declaration is met + entityId++ + } + } + + return d +} + +// Extract name and type of a field +fun parseEntityField(ln: String): Array { + // Verify prefix + if (!ln.startsWith(PREFIX_FIELD)) { + return arrayOf() + } + val prefixLen = PREFIX_FIELD.length + val nameAndValue = ln.substring(prefixLen) + val parts = nameAndValue.split(FIELD_DELIMITER, limit = 2) + if (parts.size != 2) { + return arrayOf() + } + return parts.toTypedArray() +} + +// Extract entity field comments +fun parseEntityFieldComments(lines: Array): Map> { + var d = mutableMapOf>() + var entityId = 0 + var comments = mutableMapOf() + var isParsingFields = false + var lastComment = "" + + for (ln in lines) { + val isSectionMarker = (ln == SECTION_FIELDS) + val isComment = isParsingFields && ln.startsWith(PREFIX_FIELD_COMMENT) + val isField = isParsingFields && !parseEntityField(ln).isEmpty() + val isEntityEndMarker = isParsingFields && ln.isEmpty() + val isLastEntityEndMarker = isParsingFields && (ln == lines.last()) + + if (isSectionMarker) { + isParsingFields = true + } + + if (isComment) { + val prefixLen = PREFIX_FIELD_COMMENT.length + lastComment = ln.substring(prefixLen) + } + + if ( + isField && + !lastComment.isEmpty() + ) { + val parts = parseEntityField(ln) + val name = parts[0] + comments[name] = lastComment + lastComment = "" + } + + if ( + isEntityEndMarker || + isLastEntityEndMarker + ) { + isParsingFields = false + d[entityId] = comments + entityId++ + comments = mutableMapOf() + } + } + + return d +} + +// Extract entity field name from input line +fun parseEntityFields(lines: Array): Map> { + var d = mutableMapOf>() + var entityId = 0 + var fields = mutableMapOf() + var isParsingFields = false + + for ((i, ln) in lines.withIndex()) { + val isSectionMarker = (ln == SECTION_FIELDS) + val isField = isParsingFields && !parseEntityField(ln).isEmpty() + val isEntityEndMarker = isParsingFields && ln.isEmpty() + val isLastEntityEndMarker = isParsingFields && (i == lines.size - 1) + + if (isSectionMarker) { + isParsingFields = true + } + + if (isField) { + val parts = parseEntityField(ln) + val name = parts[0] + val type = parts[1] + fields[name] = type + } + + if ( + isEntityEndMarker || + isLastEntityEndMarker + ) { + isParsingFields = false + d[entityId] = fields + entityId++ + fields = mutableMapOf() + } + } + + return d +} + +// Extract entity name from input line if it declares entity +fun parseEntityName(ln: String): String { + if ( + !ln.startsWith(" ") && + !ln.startsWith(PREFIX_ENTITY_COMMENT) && + ln != "" && + ln.endsWith(POSTFIX_ENTITY) && + ln == ln.capitalize() // The first character is capitalized + ) { + val ending = POSTFIX_ENTITY.length + return ln.dropLast(ending) + } + return "" +} + +// Collect the names of entities in the order of appearance +fun parseEntityNames(lines: Array): Array { + var items = arrayOf() + for (ln in lines) { + if (!parseEntityName(ln).isEmpty()) { + items += parseEntityName(ln) + } + } + + return items +} + +// Collect prefixes for entities +fun parseEntityPrefixes( + lines: Array, + pre: String +): Map { + var d = mutableMapOf() + var entityId = -1 + for (ln in lines) { + if (ln.startsWith(pre)) { + val prefixLen = pre.length + val value = ln.substring(prefixLen) + d[entityId] = value + } else if (!parseEntityName(ln).isEmpty()) { + entityId++ + } + } + + return d +} + +// Collect types of entities +fun parseEntityTypes(lines: Array): Map { + var d = mutableMapOf() + var entityId = -1 + for (ln in lines) { + if (ln.startsWith(PREFIX_TYPE)) { + val prefixLen = PREFIX_TYPE.length + val type = ln.substring(prefixLen) + d[entityId] = type + } else if (!parseEntityName(ln).isEmpty()) { + entityId++ + } + } + + return d +} diff --git a/klin/ver-nodejs/app/src/commonMain/kotlin/org/opengamestudio/registerOneliners.kt b/klin/ver-nodejs/app/src/commonMain/kotlin/org/opengamestudio/registerOneliners.kt new file mode 120000 index 0000000..6a0d6f2 --- /dev/null +++ b/klin/ver-nodejs/app/src/commonMain/kotlin/org/opengamestudio/registerOneliners.kt @@ -0,0 +1 @@ +../../../../../../../../src/registerOneliners.kt \ No newline at end of file diff --git a/klin/ver-nodejs/app/src/commonMain/kotlin/org/opengamestudio/templates.kt b/klin/ver-nodejs/app/src/commonMain/kotlin/org/opengamestudio/templates.kt new file mode 100644 index 0000000..96ada5d --- /dev/null +++ b/klin/ver-nodejs/app/src/commonMain/kotlin/org/opengamestudio/templates.kt @@ -0,0 +1,59 @@ +/** + * This file is a part of Kotlin dialect: + * https://github.com/OGStudio/kotlin-dialect + * License: CC0 + * Version: 2.0.0 + */ + +package org.opengamestudio + +const val TEMPLATE_KOTLIN_CONTEXT = """ +%COMMENT% +%PREFIX% +data class %NAME%( +%FIELDS% + override var recentField: String = "", +): CLDContext { + override fun field(name: String): T { +%GETTERS% } + return "unknown-field-name" as T + } + + override fun selfCopy(): CLDContext { + return this.copy() + } + + override fun setField( + name: String, + value: Any? + ) { +%SETTERS% } + } +} +""" + +const val TEMPLATE_KOTLIN_CONTEXT_GETTER = """ } else if (name == "%NAME%") { + return %NAME% as T +""" + +const val TEMPLATE_KOTLIN_CONTEXT_GETTER_FIRST = """ if (name == "%NAME%") { + return %NAME% as T +""" + +const val TEMPLATE_KOTLIN_CONTEXT_SETTER = """ } else if (name == "%NAME%") { + %NAME% = value as %TYPE% +""" + +const val TEMPLATE_KOTLIN_CONTEXT_SETTER_FIRST = """ if (name == "%NAME%") { + %NAME% = value as %TYPE% +""" + +const val TEMPLATE_KOTLIN_FIELD = " var %NAME%: %TYPE% = %DEFAULT%," + +const val TEMPLATE_KOTLIN_STRUCT = """ +%COMMENT% +%PREFIX% +data class %NAME%( +%FIELDS% +) {} +""" diff --git a/klin/ver-nodejs/app/src/jsMain/resources/app.js b/klin/ver-nodejs/app/src/jsMain/resources/app.js new file mode 100755 index 0000000..f7ee501 --- /dev/null +++ b/klin/ver-nodejs/app/src/jsMain/resources/app.js @@ -0,0 +1,68 @@ +#!/usr/bin/env node + +let fs = require("fs"); +let KT = require("./ver-nodejs-app").org.opengamestudio; + +//!<-- API --> + +function appSet(key, value) { + KT.appCtrl().set(key, value); +} + +//!<-- Constants --> + +//let APP_TMP = "BINARY"; + +//!<-- Component --> + +function AppComponent() { + this._construct = function() { + // TODO 1. Create ctrl instance in KMP + // TODO Only reference it here + // TODO 2. Accept isDbg to enabled dbg output + + // Effects + /* + let oneliners = [ + "deleteFile", (c) => { srvDeleteFile(c.deleteFile) }, + "listDir", (c) => { srvListDir(c.listDir) }, + "projectDir", (c) => { srvResolvePath(c.projectDir) }, + "readFile", (c) => { srvReadFile(c.readFile) }, + "url", (c) => { open(c.url) }, + "writeFile", (c) => { srvWriteFile(c.writeFile[0], c.writeFile[1]) }, + ]; + KT.registerOneliners(this.ctrl, oneliners); + */ + + // Defaults. + appSet("arguments", process.argv); + }; + + this._construct(); +} + +// + +/* +function srvDeleteFile(fileName) { + var isOk = true; + try { + fs.rmSync(fileName); + } catch (e) { + console.error("ERR srvDF e:", e); + isOk = false; + } + srvCtrl().set("didDeleteFile", isOk); +} +*/ + +// + + +// + +let cmp = new AppComponent(); + +// + +console.log("ИГР App hello world"); diff --git a/klin/ver-nodejs/gradle.properties b/klin/ver-nodejs/gradle.properties new file mode 100644 index 0000000..1627a5c --- /dev/null +++ b/klin/ver-nodejs/gradle.properties @@ -0,0 +1,4 @@ +# Log verbosely +org.gradle.console=verbose +# Cache artifacts +org.gradle.caching=true diff --git a/klin/ver-nodejs/gradle/libs.versions.toml b/klin/ver-nodejs/gradle/libs.versions.toml new file mode 100644 index 0000000..8a4056d --- /dev/null +++ b/klin/ver-nodejs/gradle/libs.versions.toml @@ -0,0 +1,7 @@ +[versions] +kotlin = "2.2.0" + +[libraries] + +[plugins] +kotlin-multiplatform= { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" } diff --git a/klin/ver-nodejs/gradle/wrapper/gradle-wrapper.jar b/klin/ver-nodejs/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..a4b76b9 Binary files /dev/null and b/klin/ver-nodejs/gradle/wrapper/gradle-wrapper.jar differ diff --git a/klin/ver-nodejs/gradle/wrapper/gradle-wrapper.properties b/klin/ver-nodejs/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..e0fd020 --- /dev/null +++ b/klin/ver-nodejs/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-all.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/klin/ver-nodejs/gradlew b/klin/ver-nodejs/gradlew new file mode 100755 index 0000000..f3b75f3 --- /dev/null +++ b/klin/ver-nodejs/gradlew @@ -0,0 +1,251 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/klin/ver-nodejs/kotlin-js-store/yarn.lock b/klin/ver-nodejs/kotlin-js-store/yarn.lock new file mode 100644 index 0000000..5c6c898 --- /dev/null +++ b/klin/ver-nodejs/kotlin-js-store/yarn.lock @@ -0,0 +1,514 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +ansi-colors@^4.1.3: + version "4.1.3" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.3.tgz#37611340eb2243e70cc604cad35d63270d48781b" + integrity sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw== + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +anymatch@~3.1.2: + version "3.1.3" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" + integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +binary-extensions@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522" + integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw== + +brace-expansion@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.2.tgz#54fc53237a613d854c7bd37463aad17df87214e7" + integrity sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ== + dependencies: + balanced-match "^1.0.0" + +braces@~3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== + dependencies: + fill-range "^7.1.1" + +browser-stdout@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" + integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== + +buffer-from@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== + +camelcase@^6.0.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" + integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== + +chalk@^4.1.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +chokidar@^3.5.3: + version "3.6.0" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b" + integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + +cliui@^7.0.2: + version "7.0.4" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" + integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^7.0.0" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +debug@^4.3.5: + version "4.4.3" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.3.tgz#c6ae432d9bd9662582fce08709b038c58e9e3d6a" + integrity sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA== + dependencies: + ms "^2.1.3" + +decamelize@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837" + integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ== + +diff@^5.2.0: + version "5.2.2" + resolved "https://registry.yarnpkg.com/diff/-/diff-5.2.2.tgz#0a4742797281d09cfa699b79ea32d27723623bad" + integrity sha512-vtcDfH3TOjP8UekytvnHH1o1P4FcUdt4eQ1Y+Abap1tk/OB2MWQvcwS2ClCd1zuIhc3JKOx6p3kod8Vfys3E+A== + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +escalade@^3.1.1: + version "3.2.0" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" + integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== + +escape-string-regexp@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== + dependencies: + to-regex-range "^5.0.1" + +find-up@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + +flat@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241" + integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== + +format-util@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/format-util/-/format-util-1.0.5.tgz#1ffb450c8a03e7bccffe40643180918cc297d271" + integrity sha512-varLbTj0e0yVyRpqQhuWV+8hlePAgaoFRhNFj50BNjEIrw1/DphHSObtqwskVCPWNgzwPoQrZAbfa/SBiicNeg== + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + +fsevents@~2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + +get-caller-file@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +glob-parent@~5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/glob/-/glob-8.1.0.tgz#d388f656593ef708ee3e34640fdfb99a9fd1c33e" + integrity sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^5.0.1" + once "^1.3.0" + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +he@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" + integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== + dependencies: + binary-extensions "^2.0.0" + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-glob@^4.0.1, is-glob@~4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-plain-obj@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" + integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== + +is-unicode-supported@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" + integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== + +js-yaml@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.1.tgz#854c292467705b699476e1a2decc0c8a3458806b" + integrity sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA== + dependencies: + argparse "^2.0.1" + +kotlin-web-helpers@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/kotlin-web-helpers/-/kotlin-web-helpers-2.0.0.tgz#b112096b273c1e733e0b86560998235c09a19286" + integrity sha512-xkVGl60Ygn/zuLkDPx+oHj7jeLR7hCvoNF99nhwXMn8a3ApB4lLiC9pk4ol4NHPjyoCbvQctBqvzUcp8pkqyWw== + dependencies: + format-util "^1.0.5" + +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== + dependencies: + p-locate "^5.0.0" + +log-symbols@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" + integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== + dependencies: + chalk "^4.1.0" + is-unicode-supported "^0.1.0" + +minimatch@^5.0.1, minimatch@^5.1.6: + version "5.1.6" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96" + integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g== + dependencies: + brace-expansion "^2.0.1" + +mocha@10.7.3: + version "10.7.3" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-10.7.3.tgz#ae32003cabbd52b59aece17846056a68eb4b0752" + integrity sha512-uQWxAu44wwiACGqjbPYmjo7Lg8sFrS3dQe7PP2FQI+woptP4vZXSMcfMyFL/e1yFEeEpV4RtyTpZROOKmxis+A== + dependencies: + ansi-colors "^4.1.3" + browser-stdout "^1.3.1" + chokidar "^3.5.3" + debug "^4.3.5" + diff "^5.2.0" + escape-string-regexp "^4.0.0" + find-up "^5.0.0" + glob "^8.1.0" + he "^1.2.0" + js-yaml "^4.1.0" + log-symbols "^4.1.0" + minimatch "^5.1.6" + ms "^2.1.3" + serialize-javascript "^6.0.2" + strip-json-comments "^3.1.1" + supports-color "^8.1.1" + workerpool "^6.5.1" + yargs "^16.2.0" + yargs-parser "^20.2.9" + yargs-unparser "^2.0.0" + +ms@^2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +normalize-path@^3.0.0, normalize-path@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +p-limit@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== + dependencies: + p-limit "^3.0.2" + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +picomatch@^2.0.4, picomatch@^2.2.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +randombytes@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" + integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== + dependencies: + safe-buffer "^5.1.0" + +readdirp@~3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== + dependencies: + picomatch "^2.2.1" + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== + +safe-buffer@^5.1.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +serialize-javascript@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.2.tgz#defa1e055c83bf6d59ea805d8da862254eb6a6c2" + integrity sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g== + dependencies: + randombytes "^2.1.0" + +source-map-support@0.5.21: + version "0.5.21" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" + integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map@^0.6.0: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +string-width@^4.1.0, string-width@^4.2.0: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-json-comments@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +supports-color@^8.1.1: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +workerpool@^6.5.1: + version "6.5.1" + resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.5.1.tgz#060f73b39d0caf97c6db64da004cd01b4c099544" + integrity sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA== + +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + +yargs-parser@^20.2.2, yargs-parser@^20.2.9: + version "20.2.9" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" + integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== + +yargs-unparser@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-2.0.0.tgz#f131f9226911ae5d9ad38c432fe809366c2325eb" + integrity sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA== + dependencies: + camelcase "^6.0.0" + decamelize "^4.0.0" + flat "^5.0.2" + is-plain-obj "^2.1.0" + +yargs@^16.2.0: + version "16.2.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" + integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== + dependencies: + cliui "^7.0.2" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.0" + y18n "^5.0.5" + yargs-parser "^20.2.2" + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== diff --git a/klin/ver-nodejs/settings.gradle.kts b/klin/ver-nodejs/settings.gradle.kts new file mode 100644 index 0000000..3802cb0 --- /dev/null +++ b/klin/ver-nodejs/settings.gradle.kts @@ -0,0 +1,16 @@ +pluginManagement { + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} +dependencyResolutionManagement { + repositories { + google() + mavenCentral() + } +} + +rootProject.name = "ver-nodejs" +include("app") diff --git a/src/KDContext.kt b/src/KDContext.kt new file mode 100644 index 0000000..cef3d5d --- /dev/null +++ b/src/KDContext.kt @@ -0,0 +1,44 @@ +/** + * This file is a part of Kotlin dialect: + * https://github.com/OGStudio/kotlin-dialect + * License: CC0 + * Version: 2.0.0 + */ + +package org.opengamestudio + +import kotlin.js.JsExport + +@JsExport +interface KDContext { + /** + * Name of the field that has just been changed + * + * Allows should-functions (reducers) to react only to + * relevant changes and ignore other changes of KDContext + */ + var recentField: String + + /** + * Get field's value by its name + */ + fun field(name: String): T + /** + * Erase type + * + * Used by KDController to assign recent field's value + */ + fun fieldAny(name: String): Any { + return field(name) + } + /** + * Create a copy of the KDContext derivative + * + * Used by KDController to treat all derived contexts as KDContext + */ + fun selfCopy(): KDContext + /** + * Set field's value by its name + */ + fun setField(name: String, value: Any?) +} diff --git a/src/KDController.kt b/src/KDController.kt new file mode 100644 index 0000000..8fb8226 --- /dev/null +++ b/src/KDController.kt @@ -0,0 +1,85 @@ +/** + * This file is a part of Kotlin dialect: + * https://github.com/OGStudio/kotlin-dialect + * License: CC0 + * Version: 2.0.0 + */ + +package org.opengamestudio + +import kotlin.js.JsExport + +val KD_FIELD_NONE = "none" + +@JsExport +class KDController( + var context: KDContext +) { + internal var callbacks = mutableListOf<(c: KDContext) -> Unit>() + internal var functions = mutableListOf<(c: KDContext) -> KDContext>() + var isProcessingQueue = false + internal var queue = mutableListOf() + + fun executeFunctions() { + val c = queue.removeAt(0) + context.recentField = c.recentField + context.setField(c.recentField, c.fieldAny(c.recentField)) + + for (f in functions) { + val ctx = f(context.selfCopy()) + if (ctx.recentField != KD_FIELD_NONE) { + queue.add(ctx) + } + } + + reportContext() + } + + fun processQueue() { + // Prevent recursion. + if (isProcessingQueue) { + return + } + + isProcessingQueue = true + + while (queue.size > 0) { + executeFunctions() + } + + isProcessingQueue = false + } + + fun registerCallback(cb: (c: KDContext) -> Unit) { + callbacks.add(cb) + } + + fun registerFieldCallback( + fieldName: String, + cb: (KDContext) -> Unit + ) { + callbacks.add({ c -> + if (c.recentField == fieldName) { + cb(c) + } + }) + } + + fun registerFunction(f: (KDContext) -> KDContext) { + functions.add(f) + } + + fun reportContext() { + for (cb in callbacks) { + cb(context) + } + } + + fun set(fieldName: String, value: Any) { + var c = context.selfCopy() + c.setField(fieldName, value) + c.recentField = fieldName + queue.add(c) + processQueue() + } +} diff --git a/src/registerOneliners.kt b/src/registerOneliners.kt new file mode 100644 index 0000000..e5f51db --- /dev/null +++ b/src/registerOneliners.kt @@ -0,0 +1,21 @@ +/** + * This file is a part of Kotlin dialect: + * https://github.com/OGStudio/kotlin-dialect + * License: CC0 + * Version: 2.0.0 + */ + +package org.opengamestudio + +// Register several oneliner callbacks to a controller +fun registerOneliners( + ctrl: KDController, + items: Array +) { + val halfCount = items.size / 2 + for (i in 0.. Unit + ctrl.registerFieldCallback(field, callback); + } +} diff --git a/test/main.kt b/test/main.kt new file mode 100644 index 0000000..32f2747 --- /dev/null +++ b/test/main.kt @@ -0,0 +1,26 @@ +fun main() { + print("Testing... ") + + val tests = arrayOf( + ::t01_Context_field, + ::t02_Context_field_optional, + ::t03_Context_selfCopy, + ::t04_Context_setField, + ::t05_Context_setField_optional, + ::t06_Controller_executeFunctions_set, + ::t07_Controller_processQueue, + ::t08_Controller_registerFieldCallback_match, + ::t09_Controller_registerFieldCallback_mismatch, + ::t10_registerOneliners, + ) + + var okCount = 0 + for (test in tests) { + val result = test() + if (result) { + okCount++ + } + } + val totalCount = tests.size + println("$okCount/$totalCount") +} diff --git a/test/make b/test/make new file mode 100755 index 0000000..5119b7a --- /dev/null +++ b/test/make @@ -0,0 +1,14 @@ +#!/bin/bash -e +SDIR=$(cd "$(dirname "$0")" ; pwd -P) + +kotlinc-native \ + $SDIR/../src/KDContext.kt \ + $SDIR/../src/KDController.kt \ + $SDIR/../src/registerOneliners.kt \ + $SDIR/main.kt \ + $SDIR/tests.kt \ + -o $SDIR/do-test + +# Get rid of the weird `kexe` extension on *nix +# JetBrains, seriously, drop this +mv $SDIR/do-test{.kexe,} diff --git a/test/tests.kt b/test/tests.kt new file mode 100644 index 0000000..42e4382 --- /dev/null +++ b/test/tests.kt @@ -0,0 +1,195 @@ +import org.opengamestudio.* + +private typealias EC = ExampleContext + +// Sample context used for testing +data class ExampleContext( + var didLaunch: Boolean = false, + var host: String = "", + var hostCount: Int = 0, + var sometimes: String? = null, + + override var recentField: String = "", +): KDContext { + override fun field(name: String): T { + if (name == "didLaunch") { + return didLaunch as T + } else if (name == "host") { + return host as T + } else if (name == "hostCount") { + return hostCount as T + } else if (name == "sometimes") { + return sometimes as T + } + + return "unknown-field-name" as T + } + + override fun selfCopy(): KDContext { + return this.copy() + } + + override fun setField( + name: String, + value: Any? + ) { + if (name == "didLaunch") { + didLaunch = value as Boolean + } else if (name == "host") { + host = value as String + } else if (name == "hostCount") { + hostCount = value as Int + } else if (name == "sometimes") { + sometimes = value as String? + } + } +} + +// Sample function: react to context change by changing one of the fields +fun shouldChangeDidLaunch(c: ExampleContext): ExampleContext { + if (c.recentField == "host") { + c.didLaunch = true + c.recentField = "didLaunch" + return c + } + + c.recentField = "none" + return c +} + +/// Validate field access by name +fun t01_Context_field(): Boolean { + var c = ExampleContext() + c.host = "abc" + return c.host == c.field("host") +} + +/// Validate field access by name for optional value +fun t02_Context_field_optional(): Boolean { + var c = ExampleContext() + val ok1 = c.field("sometimes") as String? == null + + c.sometimes = "def" + val ok2 = c.sometimes == c.field("sometimes") ?: "N/A" + + return ok1 && ok2 +} + +/// Validate `selfCopy()` returns the deep copy of a context +fun t03_Context_selfCopy(): Boolean { + var c1 = ExampleContext() + c1.host = "abc" + var c2 = c1.selfCopy() as ExampleContext + c2.host = "123" + return c1.host == "abc" +} + +/// Validate changing field value by name +fun t04_Context_setField(): Boolean { + var c = ExampleContext() + c.didLaunch = true + c.setField("didLaunch", false) + return c.didLaunch == false +} + +/// Validate changing field optional value by name +fun t05_Context_setField_optional(): Boolean { + var c = ExampleContext() + c.sometimes = "anything" + c.setField("sometimes", null) + val ok1 = c.field("sometimes") as String? == null + + c.setField("sometimes", "make it quick") + val ok2 = c.sometimes == c.field("sometimes") ?: "N/A" + + return ok1 && ok2 +} + +/// Validate `executeFunctions()` and `set()` +fun t06_Controller_executeFunctions_set(): Boolean { + val ctrl = KDController(ExampleContext()) + + // Disable the execution of `executeFunctions()` for testing purpose. + ctrl.isProcessingQueue = true + + ctrl.set("host", "123") + + ctrl.registerFunction({ c -> + shouldChangeDidLaunch(c as ExampleContext) + }) + + // Apply `host` value. + ctrl.executeFunctions() + // Apply `didLaunch` value. + ctrl.executeFunctions() + + val c = ctrl.context as ExampleContext + return c.host == "123" && + c.didLaunch == true +} + +/// Validate `processQueue()` +fun t07_Controller_processQueue(): Boolean { + val ctrl = KDController(ExampleContext()) + + ctrl.registerFunction({ c -> + shouldChangeDidLaunch(c as ExampleContext) + }) + ctrl.set("host", "123") + val c = ctrl.context as ExampleContext + return c.didLaunch == true +} + +/// Validate `registerFieldCallback()` if an expected field was changed +fun t08_Controller_registerFieldCallback_match(): Boolean { + var ec = ExampleContext() + ec.host = "123" + ec.recentField = "host" + var callbackHost = "" + + val ctrl = KDController(ec) + ctrl.registerFieldCallback("host", { c -> + callbackHost = (c as ExampleContext).host + }) + ctrl.reportContext() + + val c = ctrl.context as ExampleContext + return c.host == callbackHost +} + +/// Validate `registerFieldCallback()` if an unexpected field was changed, i.e., +/// callback should not be called +fun t09_Controller_registerFieldCallback_mismatch(): Boolean { + var ec = ExampleContext() + ec.host = "123" + ec.recentField = "host" + var callbackHost = "" + + val ctrl = KDController(ec) + ctrl.registerFieldCallback("didLaunch", { c -> + callbackHost = (c as ExampleContext).host + }) + ctrl.reportContext() + + return callbackHost == "" +} + +/// See if `registerOneliners()` can register several callbacks +/// into a controller +fun t10_registerOneliners(): Boolean { + var count = 0 + fun increaseCount(c: ExampleContext) { + count += 1 + } + + val oneliners = arrayOf( + "host", { c: EC -> increaseCount(c) }, + "host", { c: EC -> increaseCount(c) }, + ) + + val ctrl = KDController(ExampleContext()) + registerOneliners(ctrl, oneliners) + ctrl.set("host", "abc") + + return count == 2 +} diff --git a/util/do-tmux b/util/do-tmux new file mode 100755 index 0000000..9f57dc1 --- /dev/null +++ b/util/do-tmux @@ -0,0 +1,8 @@ +#!/bin/bash -e +SDIR=$(cd "$(dirname "$0")" ; pwd -P) + +cd $SDIR/../klin/ver-nodejs/app/src/jsMain/resources +tmux new-window -n js + +cd $SDIR/../klin/ver-nodejs/app/src/commonMain/kotlin/org/opengamestudio +tmux new-window -n kt diff --git a/util/run-klin-dbg b/util/run-klin-dbg new file mode 100755 index 0000000..0928e3d --- /dev/null +++ b/util/run-klin-dbg @@ -0,0 +1,13 @@ +#!/bin/bash -e +SDIR=$(cd "$(dirname "$0")" ; pwd -P) + +BUILD_DIR=$SDIR/../klin/ver-nodejs/build/js/packages/ver-nodejs-app/kotlin +GRADLE_DIR=$SDIR/../klin/ver-nodejs + +cd $GRADLE_DIR +./gradlew kotlinUpgradeYarnLock +./gradlew jsNodeProductionRun + +node $BUILD_DIR/app.js \ + --file=$SDIR/../klin.yml \ + --out=$SDIR/../src/klin.kt