From b604f084f070603112e699c237a514e67a6e1ee1 Mon Sep 17 00:00:00 2001 From: yebintang <553387747@qq.com> Date: Fri, 30 Oct 2026 12:20:16 +0800 Subject: [PATCH 1/2] Add Blob support to PlatformFile on web(WasmJS/JS) --- .../vinceglb/filekit/PlatformFile.web.kt | 23 +++++++++- .../vinceglb/filekit/PlatformFileWebTest.kt | 46 +++++++++++++++++++ 2 files changed, 68 insertions(+), 1 deletion(-) diff --git a/filekit-core/src/webMain/kotlin/io/github/vinceglb/filekit/PlatformFile.web.kt b/filekit-core/src/webMain/kotlin/io/github/vinceglb/filekit/PlatformFile.web.kt index e2e74518..1b32137a 100644 --- a/filekit-core/src/webMain/kotlin/io/github/vinceglb/filekit/PlatformFile.web.kt +++ b/filekit-core/src/webMain/kotlin/io/github/vinceglb/filekit/PlatformFile.web.kt @@ -12,7 +12,11 @@ import kotlinx.serialization.Serializable import org.khronos.webgl.ArrayBuffer import org.khronos.webgl.Uint8Array import org.khronos.webgl.get +import org.khronos.webgl.set +import org.w3c.files.Blob +import org.w3c.files.FilePropertyBag import org.w3c.files.FileReader +import kotlin.collections.forEachIndexed import kotlin.coroutines.resume import kotlin.coroutines.resumeWithException import kotlin.js.ExperimentalWasmJsInterop @@ -31,7 +35,24 @@ public actual data class PlatformFile( ) { public actual override fun toString(): String = path - public actual companion object + public actual companion object { + + /** + * Creates a [PlatformFile] from a browser [Blob]. + * + * Since a browser [File] is a subtype of [Blob], it can also be passed directly. + */ + @OptIn(ExperimentalWasmJsInterop::class) + public operator fun invoke(blob: Blob, name: String): PlatformFile { + val file = BrowserFile( + fileBits = listOf(blob.unsafeCast()).toJsArray(), + fileName = name, + options = FilePropertyBag(type = blob.type) + ) + return PlatformFile(webFile = WebFile.FileWrapper(file = file)) + } + + } } public actual val PlatformFile.name: String diff --git a/filekit-core/src/webTest/kotlin/io/github/vinceglb/filekit/PlatformFileWebTest.kt b/filekit-core/src/webTest/kotlin/io/github/vinceglb/filekit/PlatformFileWebTest.kt index db24a414..2b80baf4 100644 --- a/filekit-core/src/webTest/kotlin/io/github/vinceglb/filekit/PlatformFileWebTest.kt +++ b/filekit-core/src/webTest/kotlin/io/github/vinceglb/filekit/PlatformFileWebTest.kt @@ -4,6 +4,8 @@ import io.github.vinceglb.filekit.exceptions.FileKitException import io.github.vinceglb.filekit.mimeType.MimeType import io.github.vinceglb.filekit.utils.createTestFile import kotlinx.coroutines.test.runTest +import org.w3c.files.Blob +import org.w3c.files.BlobPropertyBag import kotlin.test.Test import kotlin.test.assertEquals import kotlin.test.assertFailsWith @@ -189,6 +191,50 @@ class PlatformFileWebTest { ) } + @OptIn(ExperimentalWasmJsInterop::class) + @Test + fun testPlatformFileFromBlob() = runTest { + val blob = Blob( + blobParts = listOf("Hello, World!".toJsString()).toJsArray(), + options = BlobPropertyBag(type = "text/plain") + ) + + val file = PlatformFile(blob = blob, name = platformFile.name) + + assertEquals(platformFile.name, file.name) + assertEquals(platformFile.extension, file.extension) + assertEquals(platformFile.nameWithoutExtension, file.nameWithoutExtension) + assertEquals(platformFile.size(), file.size()) + + assertEquals( + platformFile.readBytes().decodeToString(), + file.readBytes().decodeToString() + ) + assertEquals( + platformFile.readBytes().toList(), + file.readBytes().toList() + ) + assertEquals(platformFile.mimeType(), file.mimeType()) + assertTrue(file.isRegularFile()) + assertFalse(file.isDirectory()) + } + + @OptIn(ExperimentalWasmJsInterop::class) + @Test + fun testPlatformFileFromEmptyBlob() = runTest { + val blob = Blob( + blobParts = emptyList().toJsArray(), + options = BlobPropertyBag(type = "application/octet-stream") + ) + val file = PlatformFile(blob = blob, name = "empty.bin") + + assertEquals("empty.bin", file.name) + assertEquals(0L, file.size()) + assertTrue(file.readBytes().isEmpty()) + assertTrue(file.isRegularFile()) + assertFalse(file.isDirectory()) + } + private fun PlatformFile.webFileWrapper(): WebFile.FileWrapper = assertIs(webFile) } From 8dd896d27c2de743763f0deccc47048c234519f6 Mon Sep 17 00:00:00 2001 From: yebintang <553387747@qq.com> Date: Fri, 30 Oct 2026 19:20:16 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=F0=9F=8E=A8=20Add=20trailing=20commas=20an?= =?UTF-8?q?d=20clean=20up=20formatting=20in=20web=20target?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kotlin/io/github/vinceglb/filekit/PlatformFile.web.kt | 4 +--- .../io/github/vinceglb/filekit/PlatformFileWebTest.kt | 8 ++++---- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/filekit-core/src/webMain/kotlin/io/github/vinceglb/filekit/PlatformFile.web.kt b/filekit-core/src/webMain/kotlin/io/github/vinceglb/filekit/PlatformFile.web.kt index 1b32137a..58f19428 100644 --- a/filekit-core/src/webMain/kotlin/io/github/vinceglb/filekit/PlatformFile.web.kt +++ b/filekit-core/src/webMain/kotlin/io/github/vinceglb/filekit/PlatformFile.web.kt @@ -36,7 +36,6 @@ public actual data class PlatformFile( public actual override fun toString(): String = path public actual companion object { - /** * Creates a [PlatformFile] from a browser [Blob]. * @@ -47,11 +46,10 @@ public actual data class PlatformFile( val file = BrowserFile( fileBits = listOf(blob.unsafeCast()).toJsArray(), fileName = name, - options = FilePropertyBag(type = blob.type) + options = FilePropertyBag(type = blob.type), ) return PlatformFile(webFile = WebFile.FileWrapper(file = file)) } - } } diff --git a/filekit-core/src/webTest/kotlin/io/github/vinceglb/filekit/PlatformFileWebTest.kt b/filekit-core/src/webTest/kotlin/io/github/vinceglb/filekit/PlatformFileWebTest.kt index 2b80baf4..81167f3b 100644 --- a/filekit-core/src/webTest/kotlin/io/github/vinceglb/filekit/PlatformFileWebTest.kt +++ b/filekit-core/src/webTest/kotlin/io/github/vinceglb/filekit/PlatformFileWebTest.kt @@ -196,7 +196,7 @@ class PlatformFileWebTest { fun testPlatformFileFromBlob() = runTest { val blob = Blob( blobParts = listOf("Hello, World!".toJsString()).toJsArray(), - options = BlobPropertyBag(type = "text/plain") + options = BlobPropertyBag(type = "text/plain"), ) val file = PlatformFile(blob = blob, name = platformFile.name) @@ -208,11 +208,11 @@ class PlatformFileWebTest { assertEquals( platformFile.readBytes().decodeToString(), - file.readBytes().decodeToString() + file.readBytes().decodeToString(), ) assertEquals( platformFile.readBytes().toList(), - file.readBytes().toList() + file.readBytes().toList(), ) assertEquals(platformFile.mimeType(), file.mimeType()) assertTrue(file.isRegularFile()) @@ -224,7 +224,7 @@ class PlatformFileWebTest { fun testPlatformFileFromEmptyBlob() = runTest { val blob = Blob( blobParts = emptyList().toJsArray(), - options = BlobPropertyBag(type = "application/octet-stream") + options = BlobPropertyBag(type = "application/octet-stream"), ) val file = PlatformFile(blob = blob, name = "empty.bin")