├── .gitignore
├── .npmignore
├── LICENSE
├── README.md
├── file-source.sublime-project
├── index.js
├── package.json
└── test
├── hello.txt
├── index-test.js
└── utf8.txt
/.gitignore:
--------------------------------------------------------------------------------
1 | *.sublime-workspace
2 | .DS_Store
3 | dist/
4 | node_modules
5 | npm-debug.log
6 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | *.sublime-*
2 | dist/*.zip
3 | test/
4 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2013-2016, Michael Bostock
2 | All rights reserved.
3 |
4 | Redistribution and use in source and binary forms, with or without
5 | modification, are permitted provided that the following conditions are met:
6 |
7 | * Redistributions of source code must retain the above copyright notice, this
8 | list of conditions and the following disclaimer.
9 |
10 | * Redistributions in binary form must reproduce the above copyright notice,
11 | this list of conditions and the following disclaimer in the documentation
12 | and/or other materials provided with the distribution.
13 |
14 | * The name Michael Bostock may not be used to endorse or promote products
15 | derived from this software without specific prior written permission.
16 |
17 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 | DISCLAIMED. IN NO EVENT SHALL MICHAEL BOSTOCK BE LIABLE FOR ANY DIRECT,
21 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
22 | BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
24 | OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
25 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
26 | EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # file-source
2 |
3 | A [sliceable](https://github.com/mbostock/slice-source), [readable stream reader](https://streams.spec.whatwg.org/#readable-stream-reader) implementation on top of a Node [file read stream](https://nodejs.org/api/fs.html#fs_fs_createreadstream_path_options). This library allows you to write code that takes a *source* as input, and can work with either native readable streams or Node streams. For example:
4 |
5 | ```js
6 | var file = require("file-source");
7 |
8 | file("README.md")
9 | .then(function read(source) {
10 | return source.slice(40).then(value => {
11 | if (value == null) return;
12 | process.stdout.write(value);
13 | return read(source);
14 | });
15 | })
16 | .catch(error => console.error(error.stack));
17 | ```
18 |
19 | ## API Reference
20 |
21 | # file(path[, options]) [<>](https://github.com/mbostock/file-source/blob/master/index.js "Source")
22 |
23 | Returns a Promise that yields a *source* for the file at the specified *path* when the underlying file is open. The following options are allowed:
24 |
25 | * `highWaterMark` - the stream’s internal buffer size; defaults to 65,536
26 |
27 | # source.slice(length) [<>](https://github.com/mbostock/stream-source/blob/master/slice.js "Source")
28 |
29 | Returns a Promise for the next chunk of data from the underlying stream, yielding a [Uint8Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array) (a [Buffer](https://nodejs.org/api/buffer.html)) of *length* bytes, or the remaining bytes of the underlying stream if the underlying stream has more than zero but fewer than *length* bytes remaining, or null when no bytes remain in the stream.
30 |
31 | # source.read() [<>](https://github.com/mbostock/stream-source/blob/master/read.js "Source")
32 |
33 | Returns a Promise for the next chunk of data from the underlying stream. The yielded result is an object with the following properties:
34 |
35 | * `value` - a [Uint8Array](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array) (a [Buffer](https://nodejs.org/api/buffer.html)), or undefined if the stream ended
36 | * `done` - a boolean which is true if the stream ended
37 |
38 | # source.cancel() [<>](https://github.com/mbostock/slice-source/blob/master/cancel.js "Source")
39 |
40 | Returns a Promise which is resolved when the underlying stream has been destroyed.
41 |
--------------------------------------------------------------------------------
/file-source.sublime-project:
--------------------------------------------------------------------------------
1 | {
2 | "folders": [
3 | {
4 | "path": ".",
5 | "file_exclude_patterns": [
6 | "*.sublime-workspace"
7 | ],
8 | "folder_exclude_patterns": [
9 | "dist"
10 | ]
11 | }
12 | ]
13 | }
14 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | var fs = require("fs"),
2 | stream = require("stream-source");
3 |
4 | module.exports = function(path, options) {
5 | var highWaterMark = 65536;
6 | if (options && options.highWaterMark != null) highWaterMark = options.highWaterMark;
7 | return new Promise(function(resolve, reject) {
8 | var f = fs.createReadStream(path, {highWaterMark: highWaterMark});
9 | f.once("open", function() { resolve(stream(f)); });
10 | f.once("error", reject);
11 | });
12 | };
13 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "file-source",
3 | "version": "0.6.1",
4 | "description": "Read binary files in chunks, on demand, with promises.",
5 | "keywords": [
6 | "binary",
7 | "file",
8 | "reader",
9 | "fs"
10 | ],
11 | "homepage": "https://github.com/mbostock/file-source",
12 | "license": "BSD-3-Clause",
13 | "author": {
14 | "name": "Mike Bostock",
15 | "url": "https://bost.ocks.org/mike"
16 | },
17 | "main": "index.js",
18 | "repository": {
19 | "type": "git",
20 | "url": "http://github.com/mbostock/file-source.git"
21 | },
22 | "scripts": {
23 | "test": "tape 'test/**/*-test.js'",
24 | "postpublish": "git push && git push --tags"
25 | },
26 | "dependencies": {
27 | "stream-source": "0.3"
28 | },
29 | "devDependencies": {
30 | "tape": "4"
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/test/hello.txt:
--------------------------------------------------------------------------------
1 | Hello, world!
2 |
--------------------------------------------------------------------------------
/test/index-test.js:
--------------------------------------------------------------------------------
1 | var file = require("../"),
2 | tape = require("tape");
3 |
4 | tape("file(path) rejects if the specified file does not exist", function(test) {
5 | file("test/does-not-exist.txt")
6 | .then(source => {
7 | test.end("File shouldn’t exist!");
8 | }, error => {
9 | test.equal(error.code, "ENOENT");
10 | test.end();
11 | });
12 | });
13 |
14 | tape("file(path, options) can set the highWaterMark", function(test) {
15 | file("test/hello.txt", {highWaterMark: 4})
16 | .then(source => source.read()
17 | .then(result => {
18 | test.equal(result.done, false);
19 | test.equal(result.value.toString(), "Hell");
20 | return source.cancel();
21 | }))
22 | .then(() => test.end())
23 | .catch(error => test.end(error));
24 | });
25 |
26 | tape("source.read() yields {value: buffer, done: false} from the underlying file", function(test) {
27 | file("test/hello.txt")
28 | .then(source => source.read()
29 | .then(result => {
30 | test.equal(result.done, false);
31 | test.equal(result.value.toString(), "Hello, world!\n");
32 | test.end();
33 | }))
34 | .catch(error => test.end(error));
35 | });
36 |
37 | tape("source.slice(length) yields a buffer from the underlying file", function(test) {
38 | file("test/hello.txt")
39 | .then(source => source.slice(7)
40 | .then(value => {
41 | test.equal(value.toString(), "Hello, ");
42 | return source.slice(7);
43 | })
44 | .then(value => {
45 | test.equal(value.toString(), "world!\n");
46 | return source.slice(7);
47 | })
48 | .then(value => {
49 | test.equal(value, null);
50 | test.end();
51 | }))
52 | .catch(error => test.end(error));
53 | });
54 |
55 | tape("source.read() yields {value: undefined, done: true} after reading the underlying file", function(test) {
56 | file("test/hello.txt")
57 | .then(source => source.read()
58 | .then(result => {
59 | test.equal(result.done, false);
60 | test.equal(result.value.toString(), "Hello, world!\n");
61 | return source.read();
62 | })
63 | .then(result => {
64 | test.equal(result.done, true);
65 | test.equal(result.value, undefined);
66 | test.end();
67 | }))
68 | .catch(error => test.end(error));
69 | });
70 |
--------------------------------------------------------------------------------
/test/utf8.txt:
--------------------------------------------------------------------------------
1 | Héllø, wörld!
2 |
--------------------------------------------------------------------------------