Skip to content

Commit b482169

Browse files
committed
Merge pull request #26 from purescript-node/add-stream-fns
Add stream functions
2 parents 65d6005 + 3373834 commit b482169

File tree

11 files changed

+293
-23
lines changed

11 files changed

+293
-23
lines changed

bower.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,13 @@
1616
],
1717
"dependencies": {
1818
"purescript-datetime": "^0.9.0",
19-
"purescript-exceptions": "^0.3.0",
2019
"purescript-foreign": "^0.7.0",
2120
"purescript-node-buffer": "^0.2.0",
2221
"purescript-node-path": "^0.4.0",
2322
"purescript-unsafe-coerce": "^0.1.0",
24-
"purescript-nullable": "~0.2.1"
23+
"purescript-nullable": "~0.2.1",
24+
"purescript-node-streams": "~0.3.0",
25+
"purescript-exceptions": "~0.3.3"
2526
},
2627
"devDependencies": {
2728
"purescript-console": "~0.1.1"

docs/Node/FS/Stream.md

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
## Module Node.FS.Stream
2+
3+
#### `createWriteStream`
4+
5+
``` purescript
6+
createWriteStream :: forall eff. FilePath -> Eff (fs :: FS | eff) (Writable () (fs :: FS | eff))
7+
```
8+
9+
Create a Writable stream which writes data to the specified file, using
10+
the default options.
11+
12+
#### `fdCreateWriteStream`
13+
14+
``` purescript
15+
fdCreateWriteStream :: forall eff. FileDescriptor -> Eff (fs :: FS | eff) (Writable () (fs :: FS | eff))
16+
```
17+
18+
Create a Writable stream which writes data to the specified file
19+
descriptor, using the default options.
20+
21+
#### `WriteStreamOptions`
22+
23+
``` purescript
24+
type WriteStreamOptions = { flags :: FileFlags, perms :: Perms }
25+
```
26+
27+
#### `defaultWriteStreamOptions`
28+
29+
``` purescript
30+
defaultWriteStreamOptions :: WriteStreamOptions
31+
```
32+
33+
#### `createWriteStreamWith`
34+
35+
``` purescript
36+
createWriteStreamWith :: forall eff. WriteStreamOptions -> FilePath -> Eff (fs :: FS | eff) (Writable () (fs :: FS | eff))
37+
```
38+
39+
Like `createWriteStream`, but allows you to pass options.
40+
41+
#### `fdCreateWriteStreamWith`
42+
43+
``` purescript
44+
fdCreateWriteStreamWith :: forall eff. WriteStreamOptions -> FileDescriptor -> Eff (fs :: FS | eff) (Writable () (fs :: FS | eff))
45+
```
46+
47+
Like `fdCreateWriteStream`, but allows you to pass options.
48+
49+
#### `createReadStream`
50+
51+
``` purescript
52+
createReadStream :: forall eff. FilePath -> Eff (fs :: FS | eff) (Readable () (fs :: FS | eff))
53+
```
54+
55+
Create a Readable stream which reads data to the specified file, using
56+
the default options.
57+
58+
#### `fdCreateReadStream`
59+
60+
``` purescript
61+
fdCreateReadStream :: forall eff. FileDescriptor -> Eff (fs :: FS | eff) (Readable () (fs :: FS | eff))
62+
```
63+
64+
Create a Readable stream which reads data to the specified file
65+
descriptor, using the default options.
66+
67+
#### `ReadStreamOptions`
68+
69+
``` purescript
70+
type ReadStreamOptions = { flags :: FileFlags, perms :: Perms, autoClose :: Boolean }
71+
```
72+
73+
#### `defaultReadStreamOptions`
74+
75+
``` purescript
76+
defaultReadStreamOptions :: ReadStreamOptions
77+
```
78+
79+
#### `createReadStreamWith`
80+
81+
``` purescript
82+
createReadStreamWith :: forall eff. ReadStreamOptions -> FilePath -> Eff (fs :: FS | eff) (Readable () (fs :: FS | eff))
83+
```
84+
85+
Create a Readable stream which reads data from the specified file.
86+
87+
#### `fdCreateReadStreamWith`
88+
89+
``` purescript
90+
fdCreateReadStreamWith :: forall eff. ReadStreamOptions -> FileDescriptor -> Eff (fs :: FS | eff) (Readable () (fs :: FS | eff))
91+
```
92+
93+
Create a Readable stream which reads data from the specified file descriptor.
94+
95+

src/Node/FS/Async.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,6 @@
44

55
// module Node.FS.Async
66

7-
exports.fs = require('fs');
8-
97
exports.handleCallbackImpl = function (left, right, f) {
108
return function (err, value) {
119
if (err) {

src/Node/FS/Async.purs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ foreign import handleCallbackImpl ::
6161
handleCallback :: forall eff a. (Callback eff a) -> JSCallback a
6262
handleCallback cb = runFn3 handleCallbackImpl Left Right cb
6363

64-
foreign import fs ::
64+
fs ::
6565
{ rename :: Fn3 FilePath FilePath (JSCallback Unit) Unit
6666
, truncate :: Fn3 FilePath Int (JSCallback Unit) Unit
6767
, chown :: Fn4 FilePath Int Int (JSCallback Unit) Unit
@@ -85,6 +85,7 @@ foreign import fs ::
8585
, write :: Fn6 FileDescriptor Buffer BufferOffset BufferLength (Nullable FilePosition) (JSCallback ByteCount) Unit
8686
, close :: Fn2 FileDescriptor (JSCallback Unit) Unit
8787
}
88+
fs = unsafeRequireFS
8889

8990
-- | Type synonym for callback functions.
9091
type Callback eff a = Either Error a -> Eff (fs :: FS | eff) Unit

src/Node/FS/Internal.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
"use strict";
2+
// module Node.FS.Internal
3+
4+
exports.unsafeRequireFS = require("fs");

src/Node/FS/Internal.purs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,5 @@ import Unsafe.Coerce
77

88
mkEff :: forall e a. (Unit -> a) -> Eff e a
99
mkEff = unsafeCoerce
10+
11+
foreign import unsafeRequireFS :: forall props. { | props }

src/Node/FS/Stream.purs

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
module Node.FS.Stream
2+
( createWriteStream
3+
, fdCreateWriteStream
4+
, WriteStreamOptions()
5+
, defaultWriteStreamOptions
6+
, createWriteStreamWith
7+
, fdCreateWriteStreamWith
8+
, createReadStream
9+
, fdCreateReadStream
10+
, ReadStreamOptions()
11+
, defaultReadStreamOptions
12+
, createReadStreamWith
13+
, fdCreateReadStreamWith
14+
) where
15+
16+
import Prelude
17+
import Data.Maybe (Maybe(..))
18+
import Data.Function
19+
import Data.Nullable
20+
import Control.Monad.Eff
21+
import Node.Stream (Readable(), Writable())
22+
import Node.Path (FilePath())
23+
24+
import Node.FS
25+
import Node.FS.Perms (Perms())
26+
import Node.FS.Perms as Perms
27+
import Node.FS.Internal
28+
29+
fs ::
30+
{ createReadStream :: forall eff opts. Fn2 (Nullable FilePath) { | opts } (Readable () (fs :: FS | eff))
31+
, createWriteStream :: forall eff opts. Fn2 (Nullable FilePath) { | opts } (Writable () (fs :: FS | eff))
32+
}
33+
fs = unsafeRequireFS
34+
35+
readWrite :: Perms
36+
readWrite = Perms.mkPerms rw rw rw
37+
where
38+
rw = Perms.read + Perms.write
39+
40+
null :: forall a. Nullable a
41+
null = toNullable Nothing
42+
43+
nonnull :: forall a. a -> Nullable a
44+
nonnull = toNullable <<< Just
45+
46+
-- | Create a Writable stream which writes data to the specified file, using
47+
-- | the default options.
48+
createWriteStream :: forall eff.
49+
FilePath
50+
-> Eff (fs :: FS | eff) (Writable () (fs :: FS | eff))
51+
createWriteStream = createWriteStreamWith defaultWriteStreamOptions
52+
53+
-- | Create a Writable stream which writes data to the specified file
54+
-- | descriptor, using the default options.
55+
fdCreateWriteStream :: forall eff.
56+
FileDescriptor
57+
-> Eff (fs :: FS | eff) (Writable () (fs :: FS | eff))
58+
fdCreateWriteStream = fdCreateWriteStreamWith defaultWriteStreamOptions
59+
60+
type WriteStreamOptions =
61+
{ flags :: FileFlags
62+
, perms :: Perms
63+
}
64+
65+
defaultWriteStreamOptions :: WriteStreamOptions
66+
defaultWriteStreamOptions =
67+
{ flags: W
68+
, perms: readWrite
69+
}
70+
71+
-- | Like `createWriteStream`, but allows you to pass options.
72+
createWriteStreamWith :: forall eff.
73+
WriteStreamOptions
74+
-> FilePath
75+
-> Eff (fs :: FS | eff) (Writable () (fs :: FS | eff))
76+
createWriteStreamWith opts file = mkEff $ \_ -> runFn2
77+
fs.createWriteStream (nonnull file)
78+
{ mode: Perms.permsToInt opts.perms
79+
, flags: fileFlagsToNode opts.flags
80+
}
81+
82+
-- | Like `fdCreateWriteStream`, but allows you to pass options.
83+
fdCreateWriteStreamWith :: forall eff.
84+
WriteStreamOptions
85+
-> FileDescriptor
86+
-> Eff (fs :: FS | eff) (Writable () (fs :: FS | eff))
87+
fdCreateWriteStreamWith opts fd = mkEff $ \_ -> runFn2
88+
fs.createWriteStream null
89+
{ fd
90+
, mode: Perms.permsToInt opts.perms
91+
, flags: fileFlagsToNode opts.flags
92+
}
93+
94+
-- | Create a Readable stream which reads data to the specified file, using
95+
-- | the default options.
96+
createReadStream :: forall eff.
97+
FilePath
98+
-> Eff (fs :: FS | eff) (Readable () (fs :: FS | eff))
99+
createReadStream = createReadStreamWith defaultReadStreamOptions
100+
101+
-- | Create a Readable stream which reads data to the specified file
102+
-- | descriptor, using the default options.
103+
fdCreateReadStream :: forall eff.
104+
FileDescriptor
105+
-> Eff (fs :: FS | eff) (Readable () (fs :: FS | eff))
106+
fdCreateReadStream = fdCreateReadStreamWith defaultReadStreamOptions
107+
108+
type ReadStreamOptions =
109+
{ flags :: FileFlags
110+
, perms :: Perms
111+
, autoClose :: Boolean
112+
}
113+
114+
defaultReadStreamOptions :: ReadStreamOptions
115+
defaultReadStreamOptions =
116+
{ flags: R
117+
, perms: readWrite
118+
, autoClose: true
119+
}
120+
121+
-- | Create a Readable stream which reads data from the specified file.
122+
createReadStreamWith :: forall eff.
123+
ReadStreamOptions
124+
-> FilePath
125+
-> Eff (fs :: FS | eff) (Readable () (fs :: FS | eff))
126+
createReadStreamWith opts file = mkEff $ \_ -> runFn2
127+
fs.createReadStream (nonnull file)
128+
{ mode: Perms.permsToInt opts.perms
129+
, flags: fileFlagsToNode opts.flags
130+
, autoClose: opts.autoClose
131+
}
132+
133+
-- | Create a Readable stream which reads data from the specified file descriptor.
134+
fdCreateReadStreamWith :: forall eff.
135+
ReadStreamOptions
136+
-> FileDescriptor
137+
-> Eff (fs :: FS | eff) (Readable () (fs :: FS | eff))
138+
fdCreateReadStreamWith opts fd = mkEff $ \_ -> runFn2
139+
fs.createReadStream null
140+
{ fd
141+
, mode: Perms.permsToInt opts.perms
142+
, flags: fileFlagsToNode opts.flags
143+
, autoClose: opts.autoClose
144+
}

src/Node/FS/Sync.js

Lines changed: 0 additions & 17 deletions
This file was deleted.

src/Node/FS/Sync.purs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,13 +42,14 @@ import Data.Int (round)
4242
import Data.Maybe (Maybe(..))
4343
import Node.Buffer (Buffer(), BUFFER(), size)
4444
import Node.Encoding
45+
4546
import Node.FS
4647
import Node.FS.Stats
4748
import Node.Path (FilePath())
4849
import Node.FS.Perms
4950
import Node.FS.Internal
5051

51-
foreign import fs ::
52+
fs ::
5253
{ renameSync :: Fn2 FilePath FilePath Unit
5354
, truncateSync :: Fn2 FilePath Int Unit
5455
, chownSync :: Fn3 FilePath Int Int Unit
@@ -73,6 +74,7 @@ foreign import fs ::
7374
, fsyncSync :: Fn1 FileDescriptor Unit
7475
, closeSync :: Fn1 FileDescriptor Unit
7576
}
77+
fs = unsafeRequireFS
7678

7779
-- | Renames a file.
7880
rename :: forall eff. FilePath

test/Main.purs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ module Test.Main where
33
import Prelude
44
import qualified Test as Test
55
import qualified TestAsync as TestAsync
6+
import Test.Streams as Streams
67

78
main = do
89
Test.main
910
TestAsync.main
11+
Streams.main

test/Streams.purs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
module Test.Streams where
2+
3+
import Prelude
4+
import Data.Maybe
5+
import Data.Either
6+
import Control.Apply ((*>))
7+
import Control.Bind ((=<<))
8+
import Control.Monad.Eff
9+
import Control.Monad.Eff.Exception
10+
import Control.Monad.Eff.Console (log)
11+
import Node.Encoding
12+
import Node.Buffer as Buffer
13+
import Node.Path as Path
14+
import Node.Stream as Stream
15+
import Unsafe.Coerce
16+
17+
import Node.FS
18+
import Node.FS.Stats
19+
import Node.FS.Stream
20+
import Node.FS.Sync as Sync
21+
22+
main = do
23+
let fp = Path.concat
24+
25+
log "Testing streams"
26+
27+
r <- createReadStream (fp ["test", "Streams.purs"])
28+
w <- createWriteStream (fp ["tmp", "Streams.purs"])
29+
30+
Stream.pipe r w
31+
32+
Stream.onEnd r do
33+
src <- Sync.readTextFile UTF8 (fp ["test", "Streams.purs"])
34+
dst <- Sync.readTextFile UTF8 (fp ["tmp", "Streams.purs"])
35+
36+
if src == dst
37+
then log "all good"
38+
else log "not good"

0 commit comments

Comments
 (0)