Skip to content
This repository was archived by the owner on Jul 30, 2024. It is now read-only.

Commit e69c9a6

Browse files
authored
Merge pull request #165 from exoego/fs-addition
Add Fs.opendir and Fs.Dir
2 parents 200e9d2 + a0066bb commit e69c9a6

File tree

4 files changed

+108
-2
lines changed

4 files changed

+108
-2
lines changed

app/current/src/main/scala/io/scalajs/nodejs/fs/Fs.scala

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
package io.scalajs.nodejs
22
package fs
33

4-
import com.thoughtworks.enableIf
4+
import com.thoughtworks.{enableIf, enableMembersIf}
55
import io.scalajs.nodejs.buffer.Buffer
66
import io.scalajs.nodejs.events.IEventEmitter
77

@@ -559,6 +559,15 @@ trait Fs extends IEventEmitter with FSConstants {
559559
@enableIf(io.scalajs.nodejs.internal.CompilerSwitches.gteNodeJs12)
560560
def openSync(path: Path): FileDescriptor = js.native
561561

562+
@enableIf(io.scalajs.nodejs.internal.CompilerSwitches.gteNodeJs12)
563+
def opendir(path: Path, options: OpendirOptions, callback: FsCallback1[Fs.Dir]): Unit = js.native
564+
565+
@enableIf(io.scalajs.nodejs.internal.CompilerSwitches.gteNodeJs12)
566+
def opendir(path: Path, callback: FsCallback1[Fs.Dir]): Unit = js.native
567+
568+
@enableIf(io.scalajs.nodejs.internal.CompilerSwitches.gteNodeJs12)
569+
def opendirSync(path: Path, options: OpendirOptions = js.native): Fs.Dir = js.native
570+
562571
/**
563572
* Read data from the file specified by fd.
564573
* @param fd is the file descriptor
@@ -1138,7 +1147,9 @@ object Fs extends Fs {
11381147
def mkdtemp(prefix: String, encoding: String = js.native): js.Promise[String] = js.native
11391148
def open(path: Path, flags: Flags, mode: FileMode = js.native): js.Promise[FileHandle] = js.native
11401149
@enableIf(io.scalajs.nodejs.internal.CompilerSwitches.gteNodeJs12)
1141-
def open(path: Path): js.Promise[FileHandle] = js.native
1150+
def open(path: Path): js.Promise[FileHandle] = js.native
1151+
@enableIf(io.scalajs.nodejs.internal.CompilerSwitches.gteNodeJs12)
1152+
def opendir(path: Path, options: OpendirOptions = js.native): js.Promise[Dir] = js.native
11421153
def readdir(path: Path, options: ReaddirOptions): js.Promise[js.Array[String] | js.Array[Dirent]] = js.native
11431154
def readdir(path: Path, options: String | FileEncodingOptions = js.native): js.Promise[js.Array[String]] = js.native
11441155
def readlink(path: Path): js.Promise[String] = js.native
@@ -1206,6 +1217,20 @@ object Fs extends Fs {
12061217
def isSymbolicLink(): Boolean = js.native
12071218
val name: String | Buffer = js.native
12081219
}
1220+
1221+
@enableMembersIf(io.scalajs.nodejs.internal.CompilerSwitches.gteNodeJs12)
1222+
@js.native
1223+
trait Dir extends js.Object {
1224+
def close(): js.Promise[Unit] = js.native
1225+
def close(callback: js.Function1[js.Error, Any]): Unit = js.native
1226+
def closeSync(): Unit = js.native
1227+
def path: String = js.native
1228+
def read(): js.Promise[Dirent] = js.native
1229+
def read(callback: js.Function2[js.Error, Dirent, Any]): Unit = js.native
1230+
def readSync(): Dirent = js.native
1231+
1232+
// TODO: Implement AsyncIterable[Dirent]
1233+
}
12091234
}
12101235

12111236
@js.native
@@ -1231,6 +1256,9 @@ class ReaddirOptions(var encoding: js.UndefOr[String] = js.undefined,
12311256
var withFileTypes: js.UndefOr[Boolean] = js.undefined)
12321257
extends js.Object
12331258

1259+
class OpendirOptions(var encoding: js.UndefOr[String] = js.undefined, var bufferSize: js.UndefOr[Double] = js.undefined)
1260+
extends js.Object
1261+
12341262
class ReadFileOptions(var flag: js.UndefOr[String] = js.undefined) extends js.Object
12351263

12361264
class FileInputOptions(var flags: js.UndefOr[String] = js.undefined,

app/current/src/main/scala/io/scalajs/nodejs/fs/package.scala

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ package object fs {
3232

3333
/**
3434
* File System Extensions
35+
*
3536
* @param instance the given [[Fs file system]] instance
3637
*/
3738
implicit final class FsExtensions(private val instance: Fs) extends AnyVal {
@@ -194,6 +195,18 @@ package object fs {
194195
promiseWithError1[FileIOError, FileDescriptor](instance.open(path, _))
195196
}
196197

198+
@enableIf(io.scalajs.nodejs.internal.CompilerSwitches.gteNodeJs12)
199+
@inline
200+
def opendirFuture(path: Path, options: OpendirOptions): Future[Fs.Dir] = {
201+
promiseWithError1[FileIOError, Fs.Dir](instance.opendir(path, options, _))
202+
}
203+
204+
@enableIf(io.scalajs.nodejs.internal.CompilerSwitches.gteNodeJs12)
205+
@inline
206+
def opendirFuture(path: Path): Future[Fs.Dir] = {
207+
promiseWithError1[FileIOError, Fs.Dir](instance.opendir(path, _))
208+
}
209+
197210
@inline
198211
def readFuture(fd: FileDescriptor,
199212
buffer: Buffer,
@@ -447,4 +460,27 @@ package object fs {
447460
)
448461
}
449462
}
463+
464+
/**
465+
* Dir Extensions
466+
*
467+
* @param instance the given [[Fs.Dir]] instance
468+
*/
469+
implicit final class FsDirExtensions(private val instance: Fs.Dir) extends AnyVal {
470+
@enableIf(io.scalajs.nodejs.internal.CompilerSwitches.gteNodeJs12)
471+
@inline
472+
def readFuture(): Future[Option[Fs.Dirent]] = {
473+
promiseWithError1[js.Error, Option[Fs.Dirent]](f => {
474+
instance.read((err, dir) => {
475+
f(err, Option(dir))
476+
})
477+
})
478+
}
479+
480+
@enableIf(io.scalajs.nodejs.internal.CompilerSwitches.gteNodeJs12)
481+
@inline
482+
def closeFuture(): Future[Unit] = {
483+
promiseWithError0[js.Error](instance.close _)
484+
}
485+
}
450486
}

app/current/src/test/scala/io/scalajs/nodejs/fs/FsAsyncTest.scala

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ import org.scalatest.BeforeAndAfterEach
55
import scala.concurrent.ExecutionContext
66
import org.scalatest.funspec.AsyncFunSpec
77

8+
import scala.scalajs.js.JavaScriptException
9+
810
class FsAsyncTest extends AsyncFunSpec with BeforeAndAfterEach {
911
override implicit val executionContext = ExecutionContext.Implicits.global
1012

@@ -54,5 +56,24 @@ class FsAsyncTest extends AsyncFunSpec with BeforeAndAfterEach {
5456
assert(!dirExistsAfterRmdir)
5557
}
5658
}
59+
60+
it("support opendir") {
61+
for {
62+
dir <- Fs.opendirFuture("core/src")
63+
maybeFirstEntry <- dir.readFuture()
64+
maybeSecondEntry <- dir.readFuture()
65+
_ <- dir.closeFuture()
66+
} yield {
67+
assert(dir.path === "core/src")
68+
assert(maybeFirstEntry.map(_.name) === Some("main"))
69+
assert(maybeSecondEntry === None)
70+
71+
val ex = intercept[JavaScriptException] {
72+
assert(dir.readSync() === null)
73+
}
74+
assert(ex.getMessage().contains("ERR_DIR_CLOSED"))
75+
}
76+
}
77+
5778
}
5879
}

app/current/src/test/scala/io/scalajs/nodejs/fs/FsClassesTest.scala

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
package io.scalajs.nodejs.fs
22

3+
import io.scalajs.nodejs.fs
34
import org.scalatest.funspec.AnyFunSpec
45

6+
import scala.scalajs.js.JavaScriptException
7+
58
/**
69
* File System (Fs) Tests
710
*
@@ -12,4 +15,22 @@ class FsClassesTest extends AnyFunSpec {
1215
assert(new ReadStream("package.json").pending)
1316
}
1417
}
18+
19+
describe("opendir") {
20+
it("returns Dir") {
21+
val dir = fs.Fs.opendirSync("core/src")
22+
assert(dir.path === "core/src")
23+
val firstEntry = dir.readSync()
24+
assert(firstEntry.name === "main")
25+
assert(firstEntry.isDirectory())
26+
27+
assert(dir.readSync() === null)
28+
29+
dir.closeSync()
30+
val ex = intercept[JavaScriptException] {
31+
assert(dir.readSync() === null)
32+
}
33+
assert(ex.getMessage().contains("ERR_DIR_CLOSED"))
34+
}
35+
}
1536
}

0 commit comments

Comments
 (0)