diff --git a/build.gradle.kts b/build.gradle.kts index df95e53..71b3682 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -4,5 +4,5 @@ allprojects { } tasks.withType { - gradleVersion = "8.0" + gradleVersion = "8.3" } diff --git a/buildSrc/build.gradle.kts b/buildSrc/build.gradle.kts index 0201c4d..18fbf20 100644 --- a/buildSrc/build.gradle.kts +++ b/buildSrc/build.gradle.kts @@ -7,6 +7,6 @@ repositories { } dependencies { - implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:1.8.10") - implementation("org.jetbrains.kotlin:kotlin-serialization:1.8.10") + implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.10") + implementation("org.jetbrains.kotlin:kotlin-serialization:1.9.10") } diff --git a/buildSrc/src/main/kotlin/dough_base.gradle.kts b/buildSrc/src/main/kotlin/dough_base.gradle.kts index a0cd7d4..277b4be 100644 --- a/buildSrc/src/main/kotlin/dough_base.gradle.kts +++ b/buildSrc/src/main/kotlin/dough_base.gradle.kts @@ -23,13 +23,18 @@ tasks.withType { kotlin { jvm() + js { + useCommonJs() + + nodejs() + } sourceSets { commonMain { dependencies { api("org.jetbrains.kotlin:kotlin-bom") api("org.jetbrains.kotlin:kotlin-stdlib") - api("org.jetbrains.kotlinx:kotlinx-serialization-json:1.4.1") + api("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.0") } } } diff --git a/buildSrc/src/main/kotlin/dough_sample.gradle.kts b/buildSrc/src/main/kotlin/dough_sample.gradle.kts index 7747352..6d63497 100644 --- a/buildSrc/src/main/kotlin/dough_sample.gradle.kts +++ b/buildSrc/src/main/kotlin/dough_sample.gradle.kts @@ -1,13 +1,22 @@ +import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJvmCompilation +import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsExec import org.jetbrains.kotlin.gradle.targets.jvm.KotlinJvmTarget plugins { id("dough_base") } -val jvmMain = kotlin.targets.getByName("jvm").compilations.getByName("main") +val jvmMain: KotlinJvmCompilation = + kotlin.targets.getByName("jvm").compilations.getByName("main") + +kotlin { + js { + binaries.executable() + } +} tasks { - val sampleJar = register("sampleJar") { + val sampleJar = register("jvmSampleJar") { group = "application" manifest { @@ -22,7 +31,7 @@ tasks { }) } - register("runSample") { + register("jvmSampleRun") { group = "application" mainClass.set("MainKt") @@ -31,4 +40,7 @@ tasks { } assemble.get().dependsOn(sampleJar) + + val jsNodeRun = tasks.getByName("jsNodeRun") as NodeJsExec + jsNodeRun.workingDir(projectDir) } diff --git a/dough-core/src/jsMain/kotlin/gay/pizza/dough/core/JsPlatformType.kt b/dough-core/src/jsMain/kotlin/gay/pizza/dough/core/JsPlatformType.kt index 3e7c887..6ef5c2e 100644 --- a/dough-core/src/jsMain/kotlin/gay/pizza/dough/core/JsPlatformType.kt +++ b/dough-core/src/jsMain/kotlin/gay/pizza/dough/core/JsPlatformType.kt @@ -6,18 +6,16 @@ enum class JsPlatformType { Unknown; companion object { - fun current(): JsPlatformType { - val isWindowAvailable = js("typeof window") != undefined - val isProcessAvailable = js("typeof process") != undefined + val current: JsPlatformType + get() { + val isWindowAvailable = js("typeof window") != undefined + val isProcessAvailable = js("typeof process") != undefined - if (isProcessAvailable) { - return Nodejs + return when { + isProcessAvailable -> Nodejs + isWindowAvailable -> Browser + else -> Unknown + } } - - if (isWindowAvailable) { - return Browser - } - return Unknown - } } } diff --git a/dough-core/src/jsMain/kotlin/gay/pizza/dough/core/StandardClockProvider.kt b/dough-core/src/jsMain/kotlin/gay/pizza/dough/core/StandardClockProvider.kt index 0650a59..0b0cec9 100644 --- a/dough-core/src/jsMain/kotlin/gay/pizza/dough/core/StandardClockProvider.kt +++ b/dough-core/src/jsMain/kotlin/gay/pizza/dough/core/StandardClockProvider.kt @@ -2,8 +2,9 @@ package gay.pizza.dough.core import gay.pizza.dough.core.time.ClockProvider import gay.pizza.dough.core.time.UnixTime +import kotlin.js.Date object StandardClockProvider : ClockProvider { override fun now(): UnixTime = - UnixTime(js("(new Date()).getTime()") as Long) + UnixTime(Date().getTime().toLong()) } diff --git a/dough-fs/src/jsMain/kotlin/gay/pizza/dough/fs/NodeFsOperations.kt b/dough-fs/src/jsMain/kotlin/gay/pizza/dough/fs/NodeFsOperations.kt new file mode 100644 index 0000000..4db0638 --- /dev/null +++ b/dough-fs/src/jsMain/kotlin/gay/pizza/dough/fs/NodeFsOperations.kt @@ -0,0 +1,113 @@ +package gay.pizza.dough.fs + +import gay.pizza.dough.core.time.UnixTime +import gay.pizza.dough.fs.nodefs.NodeFsModule +import kotlinx.serialization.DeserializationStrategy +import kotlinx.serialization.SerializationStrategy + +object NodeFsOperations : FsOperations { + override fun exists(path: FsPath): Boolean { + TODO("Not yet implemented") + } + + override fun isDirectory(path: FsPath): Boolean { + TODO("Not yet implemented") + } + + override fun isRegularFile(path: FsPath): Boolean { + TODO("Not yet implemented") + } + + override fun isSymbolicLink(path: FsPath): Boolean { + TODO("Not yet implemented") + } + + override fun isReadable(path: FsPath): Boolean { + TODO("Not yet implemented") + } + + override fun isWritable(path: FsPath): Boolean { + TODO("Not yet implemented") + } + + override fun isExecutable(path: FsPath): Boolean { + TODO("Not yet implemented") + } + + override fun lastModified(path: FsPath): UnixTime { + TODO("Not yet implemented") + } + + override fun list(path: FsPath): Sequence { + TODO("Not yet implemented") + } + + override fun walk(path: FsPath): Sequence { + TODO("Not yet implemented") + } + + override fun visit(path: FsPath, visitor: FsPathVisitor) { + TODO("Not yet implemented") + } + + override fun readString(path: FsPath): String = + NodeFsModule.readFileSync(path.fullPathString, "utf-8") + + override fun readAllBytes(path: FsPath): ByteArray { + TODO("Not yet implemented") + } + + override fun readBytesChunked(path: FsPath, block: (ByteArray, Int) -> Unit) { + TODO("Not yet implemented") + } + + override fun readJsonFile( + path: FsPath, + deserializer: DeserializationStrategy + ): T { + TODO("Not yet implemented") + } + + override fun readLines(path: FsPath): Sequence { + TODO("Not yet implemented") + } + + override fun readJsonLines( + path: FsPath, + deserializer: DeserializationStrategy + ): Sequence { + TODO("Not yet implemented") + } + + override fun writeString(path: FsPath, content: String) { + TODO("Not yet implemented") + } + + override fun writeAllBytes(path: FsPath, bytes: ByteArray) { + TODO("Not yet implemented") + } + + override fun writeJsonFile( + path: FsPath, + serializer: SerializationStrategy, + value: T + ) { + TODO("Not yet implemented") + } + + override fun delete(path: FsPath) { + TODO("Not yet implemented") + } + + override fun deleteOnExit(path: FsPath) { + TODO("Not yet implemented") + } + + override fun deleteRecursively(path: FsPath) { + TODO("Not yet implemented") + } + + override fun createDirectories(path: FsPath) { + TODO("Not yet implemented") + } +} diff --git a/dough-fs/src/jsMain/kotlin/gay/pizza/dough/fs/NodePath.kt b/dough-fs/src/jsMain/kotlin/gay/pizza/dough/fs/NodePath.kt new file mode 100644 index 0000000..6f5d27e --- /dev/null +++ b/dough-fs/src/jsMain/kotlin/gay/pizza/dough/fs/NodePath.kt @@ -0,0 +1,18 @@ +package gay.pizza.dough.fs + +import gay.pizza.dough.fs.nodefs.NodePathModule + +class NodePath(override val fullPathString: String) : FsPath { + override val entityNameString: String + get() = NodePathModule.baseName(fullPathString) + override val parent: FsPath + get() = NodePath(fullPathString) + override val operations: FsOperations + get() = NodeFsOperations + + override fun resolve(part: String): FsPath = + NodePath(NodePathModule.resolve(fullPathString, part)) + + override fun relativeTo(path: FsPath): FsPath = + NodePath(NodePathModule.relative(fullPathString, path.fullPathString)) +} diff --git a/dough-fs/src/jsMain/kotlin/gay/pizza/dough/fs/NodejsFsProvider.kt b/dough-fs/src/jsMain/kotlin/gay/pizza/dough/fs/NodejsFsProvider.kt new file mode 100644 index 0000000..b5dc1b2 --- /dev/null +++ b/dough-fs/src/jsMain/kotlin/gay/pizza/dough/fs/NodejsFsProvider.kt @@ -0,0 +1,13 @@ +package gay.pizza.dough.fs + +import gay.pizza.dough.fs.nodefs.NodePathModule + +object NodejsFsProvider : FsProvider { + override val currentWorkingDirectory: FsPath + get() = NodePath(NodePathModule.resolve(".")) + + override val operations: FsOperations + get() = TODO() + + override fun resolve(path: String): FsPath = NodePath(NodePathModule.resolve(path)) +} diff --git a/dough-fs/src/jsMain/kotlin/gay/pizza/dough/fs/PlatformFsProvider.kt b/dough-fs/src/jsMain/kotlin/gay/pizza/dough/fs/PlatformFsProvider.kt new file mode 100644 index 0000000..e574ca7 --- /dev/null +++ b/dough-fs/src/jsMain/kotlin/gay/pizza/dough/fs/PlatformFsProvider.kt @@ -0,0 +1,3 @@ +package gay.pizza.dough.fs + +actual val PlatformFsProvider: FsProvider = NodejsFsProvider diff --git a/dough-fs/src/jsMain/kotlin/gay/pizza/dough/fs/nodefs/NodeFsModule.kt b/dough-fs/src/jsMain/kotlin/gay/pizza/dough/fs/nodefs/NodeFsModule.kt new file mode 100644 index 0000000..2450534 --- /dev/null +++ b/dough-fs/src/jsMain/kotlin/gay/pizza/dough/fs/nodefs/NodeFsModule.kt @@ -0,0 +1,11 @@ +package gay.pizza.dough.fs.nodefs + +@JsModule("node:fs") +@JsNonModule +external object NodeFsModule { + @JsName("statSync") + fun statSync(path: String): NodeFsStats + + @JsName("readFileSync") + fun readFileSync(path: String, encoding: String): String +} diff --git a/dough-fs/src/jsMain/kotlin/gay/pizza/dough/fs/nodefs/NodeFsStats.kt b/dough-fs/src/jsMain/kotlin/gay/pizza/dough/fs/nodefs/NodeFsStats.kt new file mode 100644 index 0000000..934b12f --- /dev/null +++ b/dough-fs/src/jsMain/kotlin/gay/pizza/dough/fs/nodefs/NodeFsStats.kt @@ -0,0 +1,5 @@ +package gay.pizza.dough.fs.nodefs + +external class NodeFsStats { + val size: Long +} diff --git a/dough-fs/src/jsMain/kotlin/gay/pizza/dough/fs/nodefs/NodePathModule.kt b/dough-fs/src/jsMain/kotlin/gay/pizza/dough/fs/nodefs/NodePathModule.kt new file mode 100644 index 0000000..d23f2ce --- /dev/null +++ b/dough-fs/src/jsMain/kotlin/gay/pizza/dough/fs/nodefs/NodePathModule.kt @@ -0,0 +1,17 @@ +package gay.pizza.dough.fs.nodefs + +@JsModule("node:path") +@JsNonModule +external object NodePathModule { + @JsName("basename") + fun baseName(path: String): String + + @JsName("dirname") + fun dirName(path: String): String + + @JsName("resolve") + fun resolve(vararg parts: String): String + + @JsName("relative") + fun relative(from: String, to: String): String +} diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index ccebba7..7f93135 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 42defcc..ac72c34 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 79a61d4..0adc8e1 100755 --- a/gradlew +++ b/gradlew @@ -83,10 +83,8 @@ done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit - -# 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"' +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -133,10 +131,13 @@ location of your Java installation." fi else JAVACMD=java - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + 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. @@ -197,6 +198,10 @@ if "$cygwin" || "$msys" ; then 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, and $GRADLE_OPTS can contain fragments of # shell script including quotes and variable substitutions, so put them in diff --git a/samples/cat-text/build.gradle.kts b/samples/cat-text/build.gradle.kts new file mode 100644 index 0000000..76ce41e --- /dev/null +++ b/samples/cat-text/build.gradle.kts @@ -0,0 +1,13 @@ +plugins { + dough_sample +} + +kotlin { + sourceSets { + commonMain { + dependencies { + implementation(project(":dough-fs")) + } + } + } +} diff --git a/samples/cat-text/hello.txt b/samples/cat-text/hello.txt new file mode 100644 index 0000000..557db03 --- /dev/null +++ b/samples/cat-text/hello.txt @@ -0,0 +1 @@ +Hello World diff --git a/samples/cat-text/src/commonMain/kotlin/main.kt b/samples/cat-text/src/commonMain/kotlin/main.kt new file mode 100644 index 0000000..7a632ed --- /dev/null +++ b/samples/cat-text/src/commonMain/kotlin/main.kt @@ -0,0 +1,9 @@ +import gay.pizza.dough.fs.PlatformFsProvider +import gay.pizza.dough.fs.readString + +fun main() { + val currentWorkingDirectory = PlatformFsProvider.currentWorkingDirectory + val helloTextPath = currentWorkingDirectory.resolve("hello.txt") + val content = helloTextPath.readString() + println(content) +} diff --git a/tools/ensure-new-lines.sh b/tools/ensure-new-lines.sh deleted file mode 100755 index c4f13ea..0000000 --- a/tools/ensure-new-lines.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/usr/bin/env bash -set -e - -git ls-files -z | while IFS= read -rd '' f -do - if file --mime-encoding "$f" | grep -qv binary - then - tail -c1 < "$f" | read -r _ || echo >> "$f" - fi -done