remove script

This commit is contained in:
KingMcDonalds
2025-03-22 05:50:37 -07:00
parent abe06765c4
commit 2dd8b3be92
85 changed files with 0 additions and 8740 deletions
-19
View File
@@ -1,19 +0,0 @@
The MIT License
Copyright (c) 2013 Brian J. Brennan
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-47
View File
@@ -1,47 +0,0 @@
# buffer-crc32
[![Build Status](https://secure.travis-ci.org/brianloveswords/buffer-crc32.png?branch=master)](http://travis-ci.org/brianloveswords/buffer-crc32)
crc32 that works with binary data and fancy character sets, outputs
buffer, signed or unsigned data and has tests.
Derived from the sample CRC implementation in the PNG specification: http://www.w3.org/TR/PNG/#D-CRCAppendix
# install
```
npm install buffer-crc32
```
# example
```js
var crc32 = require('buffer-crc32');
// works with buffers
var buf = Buffer([0x00, 0x73, 0x75, 0x70, 0x20, 0x62, 0x72, 0x6f, 0x00])
crc32(buf) // -> <Buffer 94 5a ab 4a>
// has convenience methods for getting signed or unsigned ints
crc32.signed(buf) // -> -1805997238
crc32.unsigned(buf) // -> 2488970058
// will cast to buffer if given a string, so you can
// directly use foreign characters safely
crc32('自動販売機') // -> <Buffer cb 03 1a c5>
// and works in append mode too
var partialCrc = crc32('hey');
var partialCrc = crc32(' ', partialCrc);
var partialCrc = crc32('sup', partialCrc);
var partialCrc = crc32(' ', partialCrc);
var finalCrc = crc32('bros', partialCrc); // -> <Buffer 47 fa 55 70>
```
# tests
This was tested against the output of zlib's crc32 method. You can run
the tests with`npm test` (requires tap)
# see also
https://github.com/alexgorbatchev/node-crc, `crc.buffer.crc32` also
supports buffer inputs and return unsigned ints (thanks @tjholowaychuk).
# license
MIT/X11
-111
View File
@@ -1,111 +0,0 @@
var Buffer = require('buffer').Buffer;
var CRC_TABLE = [
0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419,
0x706af48f, 0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4,
0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07,
0x90bf1d91, 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de,
0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, 0x136c9856,
0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4,
0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3,
0x45df5c75, 0xdcd60dcf, 0xabd13d59, 0x26d930ac, 0x51de003a,
0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599,
0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190,
0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f,
0x9fbfe4a5, 0xe8b8d433, 0x7807c9a2, 0x0f00f934, 0x9609a88e,
0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed,
0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3,
0xfbd44c65, 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2,
0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a,
0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5,
0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa, 0xbe0b1010,
0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17,
0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6,
0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615,
0x73dc1683, 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8,
0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, 0xf00f9344,
0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a,
0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1,
0xa6bc5767, 0x3fb506dd, 0x48b2364b, 0xd80d2bda, 0xaf0a1b4c,
0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef,
0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe,
0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31,
0x2cd99e8b, 0x5bdeae1d, 0x9b64c2b0, 0xec63f226, 0x756aa39c,
0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b,
0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1,
0x18b74777, 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c,
0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, 0xa00ae278,
0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7,
0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc, 0x40df0b66,
0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605,
0xcdd70693, 0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8,
0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b,
0x2d02ef8d
];
if (typeof Int32Array !== 'undefined') {
CRC_TABLE = new Int32Array(CRC_TABLE);
}
function ensureBuffer(input) {
if (Buffer.isBuffer(input)) {
return input;
}
var hasNewBufferAPI =
typeof Buffer.alloc === "function" &&
typeof Buffer.from === "function";
if (typeof input === "number") {
return hasNewBufferAPI ? Buffer.alloc(input) : new Buffer(input);
}
else if (typeof input === "string") {
return hasNewBufferAPI ? Buffer.from(input) : new Buffer(input);
}
else {
throw new Error("input must be buffer, number, or string, received " +
typeof input);
}
}
function bufferizeInt(num) {
var tmp = ensureBuffer(4);
tmp.writeInt32BE(num, 0);
return tmp;
}
function _crc32(buf, previous) {
buf = ensureBuffer(buf);
if (Buffer.isBuffer(previous)) {
previous = previous.readUInt32BE(0);
}
var crc = ~~previous ^ -1;
for (var n = 0; n < buf.length; n++) {
crc = CRC_TABLE[(crc ^ buf[n]) & 0xff] ^ (crc >>> 8);
}
return (crc ^ -1);
}
function crc32() {
return bufferizeInt(_crc32.apply(null, arguments));
}
crc32.signed = function () {
return _crc32.apply(null, arguments);
};
crc32.unsigned = function () {
return _crc32.apply(null, arguments) >>> 0;
};
module.exports = crc32;
@@ -1,39 +0,0 @@
{
"author": "Brian J. Brennan <brianloveswords@gmail.com>",
"name": "buffer-crc32",
"description": "A pure javascript CRC32 algorithm that plays nice with binary data",
"version": "0.2.13",
"licenses": [
{
"type": "MIT",
"url": "https://github.com/brianloveswords/buffer-crc32/raw/master/LICENSE"
}
],
"contributors": [
{
"name": "Vladimir Kuznetsov",
"github": "mistakster"
}
],
"homepage": "https://github.com/brianloveswords/buffer-crc32",
"repository": {
"type": "git",
"url": "git://github.com/brianloveswords/buffer-crc32.git"
},
"main": "index.js",
"scripts": {
"test": "./node_modules/.bin/tap tests/*.test.js"
},
"dependencies": {},
"devDependencies": {
"tap": "~0.2.5"
},
"optionalDependencies": {},
"engines": {
"node": "*"
},
"license": "MIT",
"files": [
"index.js"
]
}
@@ -1,33 +0,0 @@
{
"rules": {
"indent": [
2,
4,
{ "SwitchCase": 1 }
],
"quotes": [
2,
"double"
],
"linebreak-style": [
2,
"unix"
],
"semi": [
2,
"always"
],
"no-console": [
0
],
"no-trailing-spaces":
[
2
]
},
"env": {
"node": true,
"mocha": true
},
"extends": "eslint:recommended"
}
@@ -1,17 +0,0 @@
language: node_js
node_js:
- "0.10"
- "0.12"
- "1.0"
- "1.8"
- "2.0"
- "2.5"
- "3.0"
- "3.3"
- "4.0"
- "4.2"
- "5.0"
- "6"
sudo: false
script:
- "npm run lint && npm test"
@@ -1,22 +0,0 @@
The MIT License (MIT)
Copyright (c) 2015 Sarosia
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
@@ -1,33 +0,0 @@
# buffer-indexof-polyfill
[![Build Status][travis-image]][travis-url]
[![NPM Version][npm-image]][npm-url]
[![NPM Downloads][downloads-image]][downloads-url]
This is a polyfill for [`Buffer#indexOf`](https://nodejs.org/api/buffer.html#buffer_buf_indexof_value_byteoffset) and Buffer#lastIndexOf introduced in NodeJS 4.0.
## Example
```js
require("buffer-indexof-polyfill");
new Buffer("buffer").indexOf("uff") // return 1
new Buffer("buffer").indexOf("abc") // return -1
```
## Installation
```bash
npm install buffer-indexof-polyfill
```
## License
[MIT](LICENSE)
[npm-image]: https://img.shields.io/npm/v/buffer-indexof-polyfill.svg
[npm-url]: https://npmjs.org/package/buffer-indexof-polyfill
[downloads-image]: https://img.shields.io/npm/dm/buffer-indexof-polyfill.svg
[downloads-url]: https://npmjs.org/package/buffer-indexof-polyfill
[travis-image]: https://travis-ci.org/sarosia/buffer-indexof-polyfill.svg?branch=master
[travis-url]: https://travis-ci.org/sarosia/buffer-indexof-polyfill
@@ -1,73 +0,0 @@
"use strict";
var initBuffer = require("./init-buffer");
if (!Buffer.prototype.indexOf) {
Buffer.prototype.indexOf = function (value, offset) {
offset = offset || 0;
// Always wrap the input as a Buffer so that this method will support any
// data type such as array octet, string or buffer.
if (typeof value === "string" || value instanceof String) {
value = initBuffer(value);
} else if (typeof value === "number" || value instanceof Number) {
value = initBuffer([ value ]);
}
var len = value.length;
for (var i = offset; i <= this.length - len; i++) {
var mismatch = false;
for (var j = 0; j < len; j++) {
if (this[i + j] != value[j]) {
mismatch = true;
break;
}
}
if (!mismatch) {
return i;
}
}
return -1;
};
}
function bufferLastIndexOf (value, offset) {
// Always wrap the input as a Buffer so that this method will support any
// data type such as array octet, string or buffer.
if (typeof value === "string" || value instanceof String) {
value = initBuffer(value);
} else if (typeof value === "number" || value instanceof Number) {
value = initBuffer([ value ]);
}
var len = value.length;
offset = offset || this.length - len;
for (var i = offset; i >= 0; i--) {
var mismatch = false;
for (var j = 0; j < len; j++) {
if (this[i + j] != value[j]) {
mismatch = true;
break;
}
}
if (!mismatch) {
return i;
}
}
return -1;
}
if (Buffer.prototype.lastIndexOf) {
// check Buffer#lastIndexOf is usable: https://github.com/nodejs/node/issues/4604
if (initBuffer("ABC").lastIndexOf ("ABC") === -1)
Buffer.prototype.lastIndexOf = bufferLastIndexOf;
} else {
Buffer.prototype.lastIndexOf = bufferLastIndexOf;
}
@@ -1,8 +0,0 @@
module.exports = function initBuffer(val) {
// assume old version
var nodeVersion = process && process.version ? process.version : "v5.0.0";
var major = nodeVersion.split(".")[0].replace("v", "");
return major < 6
? new Buffer(val)
: Buffer.from(val);
};
@@ -1,34 +0,0 @@
{
"name": "buffer-indexof-polyfill",
"version": "1.0.2",
"description": "This is a polyfill for Buffer#indexOf introduced in NodeJS 4.0.",
"main": "index.js",
"scripts": {
"test": "mocha",
"lint": "eslint .",
"fix": "eslint . --fix"
},
"author": "https://github.com/sarosia",
"license": "MIT",
"engines": {
"node": ">=0.10"
},
"repository": {
"type": "git",
"url": "git+https://github.com/sarosia/buffer-indexof-polyfill.git"
},
"devDependencies": {
"chai": "^3.3.0",
"eslint": "^1.10.3",
"mocha": "^2.3.3"
},
"keywords": [
"buffer",
"indexof",
"polyfill"
],
"bugs": {
"url": "https://github.com/sarosia/buffer-indexof-polyfill/issues"
},
"homepage": "https://github.com/sarosia/buffer-indexof-polyfill#readme"
}
@@ -1,128 +0,0 @@
"use strict";
var expect = require("chai").expect;
var initBuffer = require("../init-buffer");
require("../index.js");
describe("Buffer#indexOf", function () {
it("Buffer as value", function () {
var buffer = initBuffer("ABC");
expect(buffer.indexOf(initBuffer("ABC"))).to.be.equal(0);
expect(buffer.indexOf(initBuffer("AB"))).to.be.equal(0);
expect(buffer.indexOf(initBuffer("BC"))).to.be.equal(1);
expect(buffer.indexOf(initBuffer("C"))).to.be.equal(2);
expect(buffer.indexOf(initBuffer("CC"))).to.be.equal(-1);
expect(buffer.indexOf(initBuffer("CA"))).to.be.equal(-1);
expect(buffer.indexOf(initBuffer("ABC"), 1)).to.be.equal(-1);
expect(buffer.indexOf(initBuffer("AB"), 1)).to.be.equal(-1);
expect(buffer.indexOf(initBuffer("BC"), 1)).to.be.equal(1);
expect(buffer.indexOf(initBuffer("C"), 1)).to.be.equal(2);
expect(buffer.indexOf(initBuffer("CC"), 1)).to.be.equal(-1);
expect(buffer.indexOf(initBuffer("CA"), 1)).to.be.equal(-1);
});
it("String as value", function () {
var buffer = initBuffer("ABC");
expect(buffer.indexOf("ABC")).to.be.equal(0);
expect(buffer.indexOf("AB")).to.be.equal(0);
expect(buffer.indexOf("BC")).to.be.equal(1);
expect(buffer.indexOf("C")).to.be.equal(2);
expect(buffer.indexOf("CC")).to.be.equal(-1);
expect(buffer.indexOf("CA")).to.be.equal(-1);
expect(buffer.indexOf("ABC", 1)).to.be.equal(-1);
expect(buffer.indexOf("AB", 1)).to.be.equal(-1);
expect(buffer.indexOf("BC", 1)).to.be.equal(1);
expect(buffer.indexOf("C", 1)).to.be.equal(2);
expect(buffer.indexOf("CC", 1)).to.be.equal(-1);
expect(buffer.indexOf("CA", 1)).to.be.equal(-1);
});
it("Number as value", function () {
var buffer = initBuffer([ 1, 2, 3 ]);
expect(buffer.indexOf(1)).to.be.equal(0);
expect(buffer.indexOf(2)).to.be.equal(1);
expect(buffer.indexOf(3)).to.be.equal(2);
expect(buffer.indexOf(4)).to.be.equal(-1);
expect(buffer.indexOf(1, 1)).to.be.equal(-1);
expect(buffer.indexOf(2, 1)).to.be.equal(1);
expect(buffer.indexOf(3, 1)).to.be.equal(2);
expect(buffer.indexOf(4, 1)).to.be.equal(-1);
});
});
describe("Buffer#lastIndexOf", function () {
it("Buffer as value", function () {
var buffer = initBuffer("ABCABC");
expect(buffer.lastIndexOf(initBuffer("ABC"))).to.be.equal(3);
expect(buffer.lastIndexOf(initBuffer("AB"))).to.be.equal(3);
expect(buffer.lastIndexOf(initBuffer("BC"))).to.be.equal(4);
expect(buffer.lastIndexOf(initBuffer("C"))).to.be.equal(5);
expect(buffer.lastIndexOf(initBuffer("CC"))).to.be.equal(-1);
expect(buffer.lastIndexOf(initBuffer("CA"))).to.be.equal(2);
expect(buffer.lastIndexOf(initBuffer("ABC"), 1)).to.be.equal(0);
expect(buffer.lastIndexOf(initBuffer("AB"), 1)).to.be.equal(0);
expect(buffer.lastIndexOf(initBuffer("BC"), 1)).to.be.equal(1);
expect(buffer.lastIndexOf(initBuffer("C"), 1)).to.be.equal(-1);
expect(buffer.lastIndexOf(initBuffer("CC"), 1)).to.be.equal(-1);
expect(buffer.lastIndexOf(initBuffer("CA"), 1)).to.be.equal(-1);
});
it("String as value", function () {
var buffer = initBuffer("ABCABC");
expect(buffer.lastIndexOf("ABC")).to.be.equal(3);
expect(buffer.lastIndexOf("AB")).to.be.equal(3);
expect(buffer.lastIndexOf("BC")).to.be.equal(4);
expect(buffer.lastIndexOf("C")).to.be.equal(5);
expect(buffer.lastIndexOf("CC")).to.be.equal(-1);
expect(buffer.lastIndexOf("CA")).to.be.equal(2);
expect(buffer.lastIndexOf("ABC", 1)).to.be.equal(0);
expect(buffer.lastIndexOf("AB", 1)).to.be.equal(0);
expect(buffer.lastIndexOf("BC", 1)).to.be.equal(1);
expect(buffer.lastIndexOf("C", 1)).to.be.equal(-1);
expect(buffer.lastIndexOf("CC", 1)).to.be.equal(-1);
expect(buffer.lastIndexOf("CA", 1)).to.be.equal(-1);
// make sure it works predictable
buffer = buffer.toString();
expect(buffer.lastIndexOf("ABC")).to.be.equal(3);
expect(buffer.lastIndexOf("AB")).to.be.equal(3);
expect(buffer.lastIndexOf("BC")).to.be.equal(4);
expect(buffer.lastIndexOf("C")).to.be.equal(5);
expect(buffer.lastIndexOf("CC")).to.be.equal(-1);
expect(buffer.lastIndexOf("CA")).to.be.equal(2);
expect(buffer.lastIndexOf("ABC", 1)).to.be.equal(0);
expect(buffer.lastIndexOf("AB", 1)).to.be.equal(0);
expect(buffer.lastIndexOf("BC", 1)).to.be.equal(1);
expect(buffer.lastIndexOf("C", 1)).to.be.equal(-1);
expect(buffer.lastIndexOf("CC", 1)).to.be.equal(-1);
expect(buffer.lastIndexOf("CA", 1)).to.be.equal(-1);
});
it("Number as value", function () {
var buffer = initBuffer([ 1, 2, 3, 1, 2, 3]);
expect(buffer.lastIndexOf(1)).to.be.equal(3);
expect(buffer.lastIndexOf(2)).to.be.equal(4);
expect(buffer.lastIndexOf(3)).to.be.equal(5);
expect(buffer.lastIndexOf(4)).to.be.equal(-1);
expect(buffer.lastIndexOf(1, 1)).to.be.equal(0);
expect(buffer.lastIndexOf(2, 1)).to.be.equal(1);
expect(buffer.lastIndexOf(3, 1)).to.be.equal(-1);
expect(buffer.lastIndexOf(4, 1)).to.be.equal(-1);
});
});
-122
View File
@@ -1,122 +0,0 @@
buffers
=======
Treat a collection of Buffers as a single contiguous partially mutable Buffer.
Where possible, operations execute without creating a new Buffer and copying
everything over.
This is a cleaner more Buffery rehash of
[bufferlist](http://github.com/substack/node-bufferlist).
example
=======
slice
-----
var Buffers = require('buffers');
var bufs = Buffers();
bufs.push(new Buffer([1,2,3]));
bufs.push(new Buffer([4,5,6,7]));
bufs.push(new Buffer([8,9,10]));
console.dir(bufs.slice(2,8))
output:
$ node examples/slice.js
<Buffer 03 04 05 06 07 08>
splice
------
var Buffers = require('buffers');
var bufs = Buffers([
new Buffer([1,2,3]),
new Buffer([4,5,6,7]),
new Buffer([8,9,10]),
]);
var removed = bufs.splice(2, 4);
console.dir({
removed : removed.slice(),
bufs : bufs.slice(),
});
output:
$ node examples/splice.js
{ removed: <Buffer 03 04 05 06>,
bufs: <Buffer 01 02 07 08 09 0a> }
methods
=======
Buffers(buffers)
----------------
Create a Buffers with an array of `Buffer`s if specified, else `[]`.
.push(buf1, buf2...)
--------------------
Push buffers onto the end. Just like `Array.prototype.push`.
.unshift(buf1, buf2...)
-----------------------
Unshift buffers onto the head. Just like `Array.prototype.unshift`.
.slice(i, j)
------------
Slice a range out of the buffer collection as if it were contiguous.
Works just like the `Array.prototype.slice` version.
.splice(i, howMany, replacements)
---------------------------------
Splice the buffer collection as if it were contiguous.
Works just like `Array.prototype.splice`, even the replacement part!
.copy(dst, dstStart, start, end)
--------------------------------
Copy the buffer collection as if it were contiguous to the `dst` Buffer with the
specified bounds.
Works just like `Buffer.prototype.copy`.
.get(i)
-------
Get a single element at index `i`.
.set(i, x)
----------
Set a single element's value at index `i`.
.indexOf(needle, offset)
----------
Find a string or buffer `needle` inside the buffer collection. Returns
the position of the search string or -1 if the search string was not
found.
Provide an `offset` to skip that number of characters at the beginning
of the search. This can be used to find additional matches.
This function will return the correct result even if the search string
is spread out over multiple internal buffers.
.toBuffer()
-----------
Convert the buffer collection to a single buffer, equivalent with `.slice(0, buffers.length)`;
.toString(encoding, start, end)
-----------
Decodes and returns a string from the buffer collection.
Works just like `Buffer.prototype.toString`
@@ -1,9 +0,0 @@
var Buffers = require('buffers');
var bufs = Buffers();
bufs.push(new Buffer([1,2,3]));
bufs.push(new Buffer([4,5,6,7]));
bufs.push(new Buffer([8,9,10]));
console.dir(bufs.slice(2,8))
// Output: <Buffer 03 04 05 06 07 08>
@@ -1,17 +0,0 @@
var Buffers = require('buffers');
var bufs = Buffers([
new Buffer([1,2,3]),
new Buffer([4,5,6,7]),
new Buffer([8,9,10]),
]);
var removed = bufs.splice(2, 4, new Buffer('ab'), new Buffer('cd'));
console.dir({
removed : removed.slice(),
bufs : bufs.slice(),
});
/* Output:
{ removed: <Buffer 03 04 05 06>,
bufs: <Buffer 01 02 07 08 09 0a> }
*/
-269
View File
@@ -1,269 +0,0 @@
module.exports = Buffers;
function Buffers (bufs) {
if (!(this instanceof Buffers)) return new Buffers(bufs);
this.buffers = bufs || [];
this.length = this.buffers.reduce(function (size, buf) {
return size + buf.length
}, 0);
}
Buffers.prototype.push = function () {
for (var i = 0; i < arguments.length; i++) {
if (!Buffer.isBuffer(arguments[i])) {
throw new TypeError('Tried to push a non-buffer');
}
}
for (var i = 0; i < arguments.length; i++) {
var buf = arguments[i];
this.buffers.push(buf);
this.length += buf.length;
}
return this.length;
};
Buffers.prototype.unshift = function () {
for (var i = 0; i < arguments.length; i++) {
if (!Buffer.isBuffer(arguments[i])) {
throw new TypeError('Tried to unshift a non-buffer');
}
}
for (var i = 0; i < arguments.length; i++) {
var buf = arguments[i];
this.buffers.unshift(buf);
this.length += buf.length;
}
return this.length;
};
Buffers.prototype.copy = function (dst, dStart, start, end) {
return this.slice(start, end).copy(dst, dStart, 0, end - start);
};
Buffers.prototype.splice = function (i, howMany) {
var buffers = this.buffers;
var index = i >= 0 ? i : this.length - i;
var reps = [].slice.call(arguments, 2);
if (howMany === undefined) {
howMany = this.length - index;
}
else if (howMany > this.length - index) {
howMany = this.length - index;
}
for (var i = 0; i < reps.length; i++) {
this.length += reps[i].length;
}
var removed = new Buffers();
var bytes = 0;
var startBytes = 0;
for (
var ii = 0;
ii < buffers.length && startBytes + buffers[ii].length < index;
ii ++
) { startBytes += buffers[ii].length }
if (index - startBytes > 0) {
var start = index - startBytes;
if (start + howMany < buffers[ii].length) {
removed.push(buffers[ii].slice(start, start + howMany));
var orig = buffers[ii];
//var buf = new Buffer(orig.length - howMany);
var buf0 = new Buffer(start);
for (var i = 0; i < start; i++) {
buf0[i] = orig[i];
}
var buf1 = new Buffer(orig.length - start - howMany);
for (var i = start + howMany; i < orig.length; i++) {
buf1[ i - howMany - start ] = orig[i]
}
if (reps.length > 0) {
var reps_ = reps.slice();
reps_.unshift(buf0);
reps_.push(buf1);
buffers.splice.apply(buffers, [ ii, 1 ].concat(reps_));
ii += reps_.length;
reps = [];
}
else {
buffers.splice(ii, 1, buf0, buf1);
//buffers[ii] = buf;
ii += 2;
}
}
else {
removed.push(buffers[ii].slice(start));
buffers[ii] = buffers[ii].slice(0, start);
ii ++;
}
}
if (reps.length > 0) {
buffers.splice.apply(buffers, [ ii, 0 ].concat(reps));
ii += reps.length;
}
while (removed.length < howMany) {
var buf = buffers[ii];
var len = buf.length;
var take = Math.min(len, howMany - removed.length);
if (take === len) {
removed.push(buf);
buffers.splice(ii, 1);
}
else {
removed.push(buf.slice(0, take));
buffers[ii] = buffers[ii].slice(take);
}
}
this.length -= removed.length;
return removed;
};
Buffers.prototype.slice = function (i, j) {
var buffers = this.buffers;
if (j === undefined) j = this.length;
if (i === undefined) i = 0;
if (j > this.length) j = this.length;
var startBytes = 0;
for (
var si = 0;
si < buffers.length && startBytes + buffers[si].length <= i;
si ++
) { startBytes += buffers[si].length }
var target = new Buffer(j - i);
var ti = 0;
for (var ii = si; ti < j - i && ii < buffers.length; ii++) {
var len = buffers[ii].length;
var start = ti === 0 ? i - startBytes : 0;
var end = ti + len >= j - i
? Math.min(start + (j - i) - ti, len)
: len
;
buffers[ii].copy(target, ti, start, end);
ti += end - start;
}
return target;
};
Buffers.prototype.pos = function (i) {
if (i < 0 || i >= this.length) throw new Error('oob');
var l = i, bi = 0, bu = null;
for (;;) {
bu = this.buffers[bi];
if (l < bu.length) {
return {buf: bi, offset: l};
} else {
l -= bu.length;
}
bi++;
}
};
Buffers.prototype.get = function get (i) {
var pos = this.pos(i);
return this.buffers[pos.buf].get(pos.offset);
};
Buffers.prototype.set = function set (i, b) {
var pos = this.pos(i);
return this.buffers[pos.buf].set(pos.offset, b);
};
Buffers.prototype.indexOf = function (needle, offset) {
if ("string" === typeof needle) {
needle = new Buffer(needle);
} else if (needle instanceof Buffer) {
// already a buffer
} else {
throw new Error('Invalid type for a search string');
}
if (!needle.length) {
return 0;
}
if (!this.length) {
return -1;
}
var i = 0, j = 0, match = 0, mstart, pos = 0;
// start search from a particular point in the virtual buffer
if (offset) {
var p = this.pos(offset);
i = p.buf;
j = p.offset;
pos = offset;
}
// for each character in virtual buffer
for (;;) {
while (j >= this.buffers[i].length) {
j = 0;
i++;
if (i >= this.buffers.length) {
// search string not found
return -1;
}
}
var char = this.buffers[i][j];
if (char == needle[match]) {
// keep track where match started
if (match == 0) {
mstart = {
i: i,
j: j,
pos: pos
};
}
match++;
if (match == needle.length) {
// full match
return mstart.pos;
}
} else if (match != 0) {
// a partial match ended, go back to match starting position
// this will continue the search at the next character
i = mstart.i;
j = mstart.j;
pos = mstart.pos;
match = 0;
}
j++;
pos++;
}
};
Buffers.prototype.toBuffer = function() {
return this.slice();
}
Buffers.prototype.toString = function(encoding, start, end) {
return this.slice(start, end).toString(encoding);
}
-14
View File
@@ -1,14 +0,0 @@
{
"name" : "buffers",
"description" : "Treat a collection of Buffers as a single contiguous partially mutable Buffer.",
"version" : "0.1.1",
"repository" : "http://github.com/substack/node-buffers.git",
"author" : "James Halliday <mail@substack.net> (http://substack.net)",
"main" : "./index",
"scripts" : {
"test" : "expresso"
},
"engines" : {
"node" : ">=0.2.0"
}
}
-209
View File
@@ -1,209 +0,0 @@
var assert = require('assert');
var Buffers = require('../');
function create (xs, split) {
var bufs = Buffers();
var offset = 0;
split.forEach(function (i) {
bufs.push(new Buffer(xs.slice(offset, offset + i)));
offset += i;
});
return bufs;
}
exports.slice = function () {
var xs = [0,1,2,3,4,5,6,7,8,9];
var splits = [ [4,2,3,1], [2,2,2,2,2], [1,6,3,1], [9,2], [10], [5,5] ];
splits.forEach(function (split) {
var bufs = create(xs, split);
assert.eql(new Buffer(xs), bufs.slice(),
'[' + xs.join(',') + ']'
+ ' != ' +
'[' + [].join.call(bufs.slice(), ',') + ']'
);
for (var i = 0; i < xs.length; i++) {
for (var j = i; j < xs.length; j++) {
var a = bufs.slice(i,j);
var b = new Buffer(xs.slice(i,j));
assert.eql(a, b,
'[' + [].join.call(a, ',') + ']'
+ ' != ' +
'[' + [].join.call(b, ',') + ']'
);
}
}
});
};
exports.splice = function () {
var xs = [0,1,2,3,4,5,6,7,8,9];
var splits = [ [4,2,3,1], [2,2,2,2,2], [1,6,3,1], [9,2], [10], [5,5] ];
splits.forEach(function (split) {
for (var i = 0; i < xs.length; i++) {
for (var j = i; j < xs.length; j++) {
var bufs = create(xs, split);
var xs_ = xs.slice();
var a_ = bufs.splice(i,j);
var a = [].slice.call(a_.slice());
var b = xs_.splice(i,j);
assert.eql(a, b,
'[' + a.join(',') + ']'
+ ' != ' +
'[' + b.join(',') + ']'
);
assert.eql(bufs.slice(), new Buffer(xs_),
'[' + [].join.call(bufs.slice(), ',') + ']'
+ ' != ' +
'[' + [].join.call(xs_, ',') + ']'
);
}
}
});
};
exports.spliceRep = function () {
var xs = [0,1,2,3,4,5,6,7,8,9];
var splits = [ [4,2,3,1], [2,2,2,2,2], [1,6,3,1], [9,2], [10], [5,5] ];
var reps = [ [], [1], [5,6], [3,1,3,3,7], [9,8,7,6,5,4,3,2,1,2,3,4,5] ];
splits.forEach(function (split) {
reps.forEach(function (rep) {
for (var i = 0; i < xs.length; i++) {
for (var j = i; j < xs.length; j++) {
var bufs = create(xs, split);
var xs_ = xs.slice();
var a_ = bufs.splice.apply(
bufs, [ i, j ].concat(new Buffer(rep))
);
var a = [].slice.call(a_.slice());
var b = xs_.splice.apply(xs_, [ i, j ].concat(rep));
assert.eql(a, b,
'[' + a.join(',') + ']'
+ ' != ' +
'[' + b.join(',') + ']'
);
assert.eql(bufs.slice(), new Buffer(xs_),
'[' + [].join.call(bufs.slice(), ',') + ']'
+ ' != ' +
'[' + [].join.call(xs_, ',') + ']'
);
}
}
});
});
};
exports.copy = function () {
var xs = [0,1,2,3,4,5,6,7,8,9];
var splits = [ [4,2,3,1], [2,2,2,2,2], [1,6,3,1], [9,2], [10], [5,5] ];
splits.forEach(function (split) {
var bufs = create(xs, split);
var buf = new Buffer(xs);
for (var i = 0; i < xs.length; i++) {
for (var j = i; j < xs.length; j++) {
var t0 = new Buffer(j - i);
var t1 = new Buffer(j - i);
assert.eql(
bufs.copy(t0, 0, i, j),
buf.copy(t1, 0, i, j)
);
assert.eql(
[].slice.call(t0),
[].slice.call(t1)
);
}
}
});
};
exports.push = function () {
var bufs = Buffers();
bufs.push(new Buffer([0]));
bufs.push(new Buffer([1,2,3]));
bufs.push(new Buffer([4,5]));
bufs.push(new Buffer([6,7,8,9]));
assert.eql(
[].slice.call(bufs.slice()),
[0,1,2,3,4,5,6,7,8,9]
);
assert.throws(function () {
bufs.push(new Buffer([11,12]), 'moo');
});
assert.eql(bufs.buffers.length, 4);
};
exports.unshift = function () {
var bufs = Buffers();
bufs.unshift(new Buffer([6,7,8,9]));
bufs.unshift(new Buffer([4,5]));
bufs.unshift(new Buffer([1,2,3]));
bufs.unshift(new Buffer([0]));
assert.eql(
[].slice.call(bufs.slice()),
[0,1,2,3,4,5,6,7,8,9]
);
assert.throws(function () {
bufs.unshift(new Buffer([-2,-1]), 'moo');
});
assert.eql(bufs.buffers.length, 4);
};
exports.get = function () {
var bufs = Buffers();
bufs.unshift(new Buffer([6,7,8,9]));
bufs.unshift(new Buffer([4,5]));
bufs.unshift(new Buffer([1,2,3]));
bufs.unshift(new Buffer([0]));
assert.eql( bufs.get(0), 0 );
assert.eql( bufs.get(1), 1 );
assert.eql( bufs.get(2), 2 );
assert.eql( bufs.get(3), 3 );
assert.eql( bufs.get(4), 4 );
assert.eql( bufs.get(5), 5 );
assert.eql( bufs.get(6), 6 );
assert.eql( bufs.get(7), 7 );
assert.eql( bufs.get(8), 8 );
assert.eql( bufs.get(9), 9 );
};
exports.set = function () {
var bufs = Buffers();
bufs.push(new Buffer("Hel"));
bufs.push(new Buffer("lo"));
bufs.push(new Buffer("!"));
bufs.set(0, 'h'.charCodeAt(0) );
bufs.set(3, 'L'.charCodeAt(0) );
bufs.set(5, '.'.charCodeAt(0) );
assert.eql( bufs.slice(0).toString(), 'helLo.' );
};
exports.indexOf = function () {
var bufs = Buffers();
bufs.push(new Buffer("Hel"));
bufs.push(new Buffer("lo,"));
bufs.push(new Buffer(" how are "));
bufs.push(new Buffer("you"));
bufs.push(new Buffer("?"));
assert.eql( bufs.indexOf("Hello"), 0 );
assert.eql( bufs.indexOf("Hello", 1), -1 );
assert.eql( bufs.indexOf("ello"), 1 );
assert.eql( bufs.indexOf("ello", 1), 1 );
assert.eql( bufs.indexOf("ello", 2), -1 );
assert.eql( bufs.indexOf("e"), 1 );
assert.eql( bufs.indexOf("e", 2), 13 );
assert.eql( bufs.indexOf(new Buffer([0x65]), 2), 13 );
};
-1
View File
@@ -1 +0,0 @@
node_modules
-157
View File
@@ -1,157 +0,0 @@
Chainsaw
========
Build chainable fluent interfaces the easy way in node.js.
With this meta-module you can write modules with chainable interfaces.
Chainsaw takes care of all of the boring details and makes nested flow control
super simple too.
Just call `Chainsaw` with a constructor function like in the examples below.
In your methods, just do `saw.next()` to move along to the next event and
`saw.nest()` to create a nested chain.
Examples
========
add_do.js
---------
This silly example adds values with a chainsaw.
var Chainsaw = require('chainsaw');
function AddDo (sum) {
return Chainsaw(function (saw) {
this.add = function (n) {
sum += n;
saw.next();
};
this.do = function (cb) {
saw.nest(cb, sum);
};
});
}
AddDo(0)
.add(5)
.add(10)
.do(function (sum) {
if (sum > 12) this.add(-10);
})
.do(function (sum) {
console.log('Sum: ' + sum);
})
;
Output:
Sum: 5
prompt.js
---------
This example provides a wrapper on top of stdin with the help of
[node-lazy](https://github.com/pkrumins/node-lazy) for line-processing.
var Chainsaw = require('chainsaw');
var Lazy = require('lazy');
module.exports = Prompt;
function Prompt (stream) {
var waiting = [];
var lines = [];
var lazy = Lazy(stream).lines.map(String)
.forEach(function (line) {
if (waiting.length) {
var w = waiting.shift();
w(line);
}
else lines.push(line);
})
;
var vars = {};
return Chainsaw(function (saw) {
this.getline = function (f) {
var g = function (line) {
saw.nest(f, line, vars);
};
if (lines.length) g(lines.shift());
else waiting.push(g);
};
this.do = function (cb) {
saw.nest(cb, vars);
};
});
}
And now for the new Prompt() module in action:
var util = require('util');
var stdin = process.openStdin();
Prompt(stdin)
.do(function () {
util.print('x = ');
})
.getline(function (line, vars) {
vars.x = parseInt(line, 10);
})
.do(function () {
util.print('y = ');
})
.getline(function (line, vars) {
vars.y = parseInt(line, 10);
})
.do(function (vars) {
if (vars.x + vars.y < 10) {
util.print('z = ');
this.getline(function (line) {
vars.z = parseInt(line, 10);
})
}
else {
vars.z = 0;
}
})
.do(function (vars) {
console.log('x + y + z = ' + (vars.x + vars.y + vars.z));
process.exit();
})
;
Installation
============
With [npm](http://github.com/isaacs/npm), just do:
npm install chainsaw
or clone this project on github:
git clone http://github.com/substack/node-chainsaw.git
To run the tests with [expresso](http://github.com/visionmedia/expresso),
just do:
expresso
Light Mode vs Full Mode
=======================
`node-chainsaw` supports two different modes. In full mode, every
action is recorded, which allows you to replay actions using the
`jump()`, `trap()` and `down()` methods.
However, if your chainsaws are long-lived, recording every action can
consume a tremendous amount of memory, so we also offer a "light" mode
where actions are not recorded and the aforementioned methods are
disabled.
To enable light mode simply use `Chainsaw.light()` to construct your
saw, instead of `Chainsaw()`.
@@ -1,25 +0,0 @@
var Chainsaw = require('chainsaw');
function AddDo (sum) {
return Chainsaw(function (saw) {
this.add = function (n) {
sum += n;
saw.next();
};
this.do = function (cb) {
saw.nest(cb, sum);
};
});
}
AddDo(0)
.add(5)
.add(10)
.do(function (sum) {
if (sum > 12) this.add(-10);
})
.do(function (sum) {
console.log('Sum: ' + sum);
})
;
@@ -1,67 +0,0 @@
var Chainsaw = require('chainsaw');
var Lazy = require('lazy');
module.exports = Prompt;
function Prompt (stream) {
var waiting = [];
var lines = [];
var lazy = Lazy(stream).lines.map(String)
.forEach(function (line) {
if (waiting.length) {
var w = waiting.shift();
w(line);
}
else lines.push(line);
})
;
var vars = {};
return Chainsaw(function (saw) {
this.getline = function (f) {
var g = function (line) {
saw.nest(f, line, vars);
};
if (lines.length) g(lines.shift());
else waiting.push(g);
};
this.do = function (cb) {
saw.nest(cb, vars);
};
});
}
var util = require('util');
if (__filename === process.argv[1]) {
var stdin = process.openStdin();
Prompt(stdin)
.do(function () {
util.print('x = ');
})
.getline(function (line, vars) {
vars.x = parseInt(line, 10);
})
.do(function () {
util.print('y = ');
})
.getline(function (line, vars) {
vars.y = parseInt(line, 10);
})
.do(function (vars) {
if (vars.x + vars.y < 10) {
util.print('z = ');
this.getline(function (line) {
vars.z = parseInt(line, 10);
})
}
else {
vars.z = 0;
}
})
.do(function (vars) {
console.log('x + y + z = ' + (vars.x + vars.y + vars.z));
process.exit();
})
;
}
-145
View File
@@ -1,145 +0,0 @@
var Traverse = require('traverse');
var EventEmitter = require('events').EventEmitter;
module.exports = Chainsaw;
function Chainsaw (builder) {
var saw = Chainsaw.saw(builder, {});
var r = builder.call(saw.handlers, saw);
if (r !== undefined) saw.handlers = r;
saw.record();
return saw.chain();
};
Chainsaw.light = function ChainsawLight (builder) {
var saw = Chainsaw.saw(builder, {});
var r = builder.call(saw.handlers, saw);
if (r !== undefined) saw.handlers = r;
return saw.chain();
};
Chainsaw.saw = function (builder, handlers) {
var saw = new EventEmitter;
saw.handlers = handlers;
saw.actions = [];
saw.chain = function () {
var ch = Traverse(saw.handlers).map(function (node) {
if (this.isRoot) return node;
var ps = this.path;
if (typeof node === 'function') {
this.update(function () {
saw.actions.push({
path : ps,
args : [].slice.call(arguments)
});
return ch;
});
}
});
process.nextTick(function () {
saw.emit('begin');
saw.next();
});
return ch;
};
saw.pop = function () {
return saw.actions.shift();
};
saw.next = function () {
var action = saw.pop();
if (!action) {
saw.emit('end');
}
else if (!action.trap) {
var node = saw.handlers;
action.path.forEach(function (key) { node = node[key] });
node.apply(saw.handlers, action.args);
}
};
saw.nest = function (cb) {
var args = [].slice.call(arguments, 1);
var autonext = true;
if (typeof cb === 'boolean') {
var autonext = cb;
cb = args.shift();
}
var s = Chainsaw.saw(builder, {});
var r = builder.call(s.handlers, s);
if (r !== undefined) s.handlers = r;
// If we are recording...
if ("undefined" !== typeof saw.step) {
// ... our children should, too
s.record();
}
cb.apply(s.chain(), args);
if (autonext !== false) s.on('end', saw.next);
};
saw.record = function () {
upgradeChainsaw(saw);
};
['trap', 'down', 'jump'].forEach(function (method) {
saw[method] = function () {
throw new Error("To use the trap, down and jump features, please "+
"call record() first to start recording actions.");
};
});
return saw;
};
function upgradeChainsaw(saw) {
saw.step = 0;
// override pop
saw.pop = function () {
return saw.actions[saw.step++];
};
saw.trap = function (name, cb) {
var ps = Array.isArray(name) ? name : [name];
saw.actions.push({
path : ps,
step : saw.step,
cb : cb,
trap : true
});
};
saw.down = function (name) {
var ps = (Array.isArray(name) ? name : [name]).join('/');
var i = saw.actions.slice(saw.step).map(function (x) {
if (x.trap && x.step <= saw.step) return false;
return x.path.join('/') == ps;
}).indexOf(true);
if (i >= 0) saw.step += i;
else saw.step = saw.actions.length;
var act = saw.actions[saw.step - 1];
if (act && act.trap) {
// It's a trap!
saw.step = act.step;
act.cb();
}
else saw.next();
};
saw.jump = function (step) {
saw.step = step;
saw.next();
};
};
-23
View File
@@ -1,23 +0,0 @@
{
"name" : "chainsaw",
"version" : "0.1.0",
"description" : "Build chainable fluent interfaces the easy way... with a freakin' chainsaw!",
"main" : "./index.js",
"repository" : {
"type" : "git",
"url" : "http://github.com/substack/node-chainsaw.git"
},
"dependencies" : {
"traverse" : ">=0.3.0 <0.4"
},
"keywords" : [
"chain",
"fluent",
"interface",
"monad",
"monadic"
],
"author" : "James Halliday <mail@substack.net> (http://substack.net)",
"license" : "MIT/X11",
"engine" : { "node" : ">=0.4.0" }
}
@@ -1,418 +0,0 @@
var assert = require('assert');
var Chainsaw = require('../index');
exports.getset = function () {
var to = setTimeout(function () {
assert.fail('builder never fired');
}, 1000);
var ch = Chainsaw(function (saw) {
clearTimeout(to);
var num = 0;
this.get = function (cb) {
cb(num);
saw.next();
};
this.set = function (n) {
num = n;
saw.next();
};
var ti = setTimeout(function () {
assert.fail('end event not emitted');
}, 50);
saw.on('end', function () {
clearTimeout(ti);
assert.equal(times, 3);
});
});
var times = 0;
ch
.get(function (x) {
assert.equal(x, 0);
times ++;
})
.set(10)
.get(function (x) {
assert.equal(x, 10);
times ++;
})
.set(20)
.get(function (x) {
assert.equal(x, 20);
times ++;
})
;
};
exports.nest = function () {
var ch = (function () {
var vars = {};
return Chainsaw(function (saw) {
this.do = function (cb) {
saw.nest(cb, vars);
};
});
})();
var order = [];
var to = setTimeout(function () {
assert.fail("Didn't get to the end");
}, 50);
ch
.do(function (vars) {
vars.x = 'y';
order.push(1);
this
.do(function (vs) {
order.push(2);
vs.x = 'x';
})
.do(function (vs) {
order.push(3);
vs.z = 'z';
})
;
})
.do(function (vars) {
vars.y = 'y';
order.push(4);
})
.do(function (vars) {
assert.eql(order, [1,2,3,4]);
assert.eql(vars, { x : 'x', y : 'y', z : 'z' });
clearTimeout(to);
})
;
};
exports.nestWait = function () {
var ch = (function () {
var vars = {};
return Chainsaw(function (saw) {
this.do = function (cb) {
saw.nest(cb, vars);
};
this.wait = function (n) {
setTimeout(function () {
saw.next();
}, n);
};
});
})();
var order = [];
var to = setTimeout(function () {
assert.fail("Didn't get to the end");
}, 1000);
var times = {};
ch
.do(function (vars) {
vars.x = 'y';
order.push(1);
this
.do(function (vs) {
order.push(2);
vs.x = 'x';
times.x = Date.now();
})
.wait(50)
.do(function (vs) {
order.push(3);
vs.z = 'z';
times.z = Date.now();
var dt = times.z - times.x;
assert.ok(dt >= 50 && dt < 75);
})
;
})
.do(function (vars) {
vars.y = 'y';
order.push(4);
times.y = Date.now();
})
.wait(100)
.do(function (vars) {
assert.eql(order, [1,2,3,4]);
assert.eql(vars, { x : 'x', y : 'y', z : 'z' });
clearTimeout(to);
times.end = Date.now();
var dt = times.end - times.y;
assert.ok(dt >= 100 && dt < 125)
})
;
};
exports.nestNext = function () {
var ch = (function () {
var vars = {};
return Chainsaw(function (saw) {
this.do = function (cb) {
saw.nest(false, function () {
var args = [].slice.call(arguments);
args.push(saw.next);
cb.apply(this, args);
}, vars);
};
});
})();
var order = [];
var to = setTimeout(function () {
assert.fail("Didn't get to the end");
}, 500);
var times = [];
ch
.do(function (vars, next_) {
vars.x = 'y';
order.push(1);
this
.do(function (vs, next) {
order.push(2);
vs.x = 'x';
setTimeout(next, 30);
})
.do(function (vs, next) {
order.push(3);
vs.z = 'z';
setTimeout(next, 10);
})
.do(function () {
setTimeout(next_, 20);
})
;
})
.do(function (vars, next) {
vars.y = 'y';
order.push(4);
setTimeout(next, 5);
})
.do(function (vars) {
assert.eql(order, [1,2,3,4]);
assert.eql(vars, { x : 'x', y : 'y', z : 'z' });
clearTimeout(to);
})
;
};
exports.builder = function () {
var cx = Chainsaw(function (saw) {
this.x = function () {};
});
assert.ok(cx.x);
var cy = Chainsaw(function (saw) {
return { y : function () {} };
});
assert.ok(cy.y);
var cz = Chainsaw(function (saw) {
return { z : function (cb) { saw.nest(cb) } };
});
assert.ok(cz.z);
var to = setTimeout(function () {
assert.fail("Nested z didn't run");
}, 50);
cz.z(function () {
clearTimeout(to);
assert.ok(this.z);
});
};
this.attr = function () {
var to = setTimeout(function () {
assert.fail("attr chain didn't finish");
}, 50);
var xy = [];
var ch = Chainsaw(function (saw) {
this.h = {
x : function () {
xy.push('x');
saw.next();
},
y : function () {
xy.push('y');
saw.next();
assert.eql(xy, ['x','y']);
clearTimeout(to);
}
};
});
assert.ok(ch.h);
assert.ok(ch.h.x);
assert.ok(ch.h.y);
ch.h.x().h.y();
};
exports.down = function () {
var error = null;
var s;
var ch = Chainsaw(function (saw) {
s = saw;
this.raise = function (err) {
error = err;
saw.down('catch');
};
this.do = function (cb) {
cb.call(this);
};
this.catch = function (cb) {
if (error) {
saw.nest(cb, error);
error = null;
}
else saw.next();
};
});
var to = setTimeout(function () {
assert.fail(".do() after .catch() didn't fire");
}, 50);
ch
.do(function () {
this.raise('pow');
})
.do(function () {
assert.fail("raise didn't skip over this do block");
})
.catch(function (err) {
assert.equal(err, 'pow');
})
.do(function () {
clearTimeout(to);
})
;
};
exports.trap = function () {
var error = null;
var ch = Chainsaw(function (saw) {
var pars = 0;
var stack = [];
var i = 0;
this.par = function (cb) {
pars ++;
var j = i ++;
cb.call(function () {
pars --;
stack[j] = [].slice.call(arguments);
saw.down('result');
});
saw.next();
};
this.join = function (cb) {
saw.trap('result', function () {
if (pars == 0) {
cb.apply(this, stack);
saw.next();
}
});
};
this.raise = function (err) {
error = err;
saw.down('catch');
};
this.do = function (cb) {
cb.call(this);
};
this.catch = function (cb) {
if (error) {
saw.nest(cb, error);
error = null;
}
else saw.next();
};
});
var to = setTimeout(function () {
assert.fail(".do() after .join() didn't fire");
}, 100);
var tj = setTimeout(function () {
assert.fail('.join() never fired');
}, 100);
var joined = false;
ch
.par(function () {
setTimeout(this.bind(null, 1), 50);
})
.par(function () {
setTimeout(this.bind(null, 2), 25);
})
.join(function (x, y) {
assert.equal(x[0], 1);
assert.equal(y[0], 2);
clearTimeout(tj);
joined = true;
})
.do(function () {
clearTimeout(to);
assert.ok(joined);
})
;
};
exports.jump = function () {
var to = setTimeout(function () {
assert.fail('builder never fired');
}, 50);
var xs = [ 4, 5, 6, -4, 8, 9, -1, 8 ];
var xs_ = [];
var ch = Chainsaw(function (saw) {
this.x = function (i) {
xs_.push(i);
saw.next();
};
this.y = function (step) {
var x = xs.shift();
if (x > 0) saw.jump(step);
else saw.next();
};
saw.on('end', function () {
clearTimeout(to);
assert.eql(xs, [ 8 ]);
assert.eql(xs_, [ 1, 1, 1, 1, 2, 3, 2, 3, 2, 3 ]);
});
});
ch
.x(1)
.y(0)
.x(2)
.x(3)
.y(2)
;
};
@@ -1,4 +0,0 @@
language: node_js
node_js:
- 0.4
- 0.6
-18
View File
@@ -1,18 +0,0 @@
This software is released under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -1,62 +0,0 @@
concat-map
==========
Concatenative mapdashery.
[![browser support](http://ci.testling.com/substack/node-concat-map.png)](http://ci.testling.com/substack/node-concat-map)
[![build status](https://secure.travis-ci.org/substack/node-concat-map.png)](http://travis-ci.org/substack/node-concat-map)
example
=======
``` js
var concatMap = require('concat-map');
var xs = [ 1, 2, 3, 4, 5, 6 ];
var ys = concatMap(xs, function (x) {
return x % 2 ? [ x - 0.1, x, x + 0.1 ] : [];
});
console.dir(ys);
```
***
```
[ 0.9, 1, 1.1, 2.9, 3, 3.1, 4.9, 5, 5.1 ]
```
methods
=======
``` js
var concatMap = require('concat-map')
```
concatMap(xs, fn)
-----------------
Return an array of concatenated elements by calling `fn(x, i)` for each element
`x` and each index `i` in the array `xs`.
When `fn(x, i)` returns an array, its result will be concatenated with the
result array. If `fn(x, i)` returns anything else, that value will be pushed
onto the end of the result array.
install
=======
With [npm](http://npmjs.org) do:
```
npm install concat-map
```
license
=======
MIT
notes
=====
This module was written while sitting high above the ground in a tree.
@@ -1,6 +0,0 @@
var concatMap = require('../');
var xs = [ 1, 2, 3, 4, 5, 6 ];
var ys = concatMap(xs, function (x) {
return x % 2 ? [ x - 0.1, x, x + 0.1 ] : [];
});
console.dir(ys);
-13
View File
@@ -1,13 +0,0 @@
module.exports = function (xs, fn) {
var res = [];
for (var i = 0; i < xs.length; i++) {
var x = fn(xs[i], i);
if (isArray(x)) res.push.apply(res, x);
else res.push(x);
}
return res;
};
var isArray = Array.isArray || function (xs) {
return Object.prototype.toString.call(xs) === '[object Array]';
};
-43
View File
@@ -1,43 +0,0 @@
{
"name" : "concat-map",
"description" : "concatenative mapdashery",
"version" : "0.0.1",
"repository" : {
"type" : "git",
"url" : "git://github.com/substack/node-concat-map.git"
},
"main" : "index.js",
"keywords" : [
"concat",
"concatMap",
"map",
"functional",
"higher-order"
],
"directories" : {
"example" : "example",
"test" : "test"
},
"scripts" : {
"test" : "tape test/*.js"
},
"devDependencies" : {
"tape" : "~2.4.0"
},
"license" : "MIT",
"author" : {
"name" : "James Halliday",
"email" : "mail@substack.net",
"url" : "http://substack.net"
},
"testling" : {
"files" : "test/*.js",
"browsers" : {
"ie" : [ 6, 7, 8, 9 ],
"ff" : [ 3.5, 10, 15.0 ],
"chrome" : [ 10, 22 ],
"safari" : [ 5.1 ],
"opera" : [ 12 ]
}
}
}
-39
View File
@@ -1,39 +0,0 @@
var concatMap = require('../');
var test = require('tape');
test('empty or not', function (t) {
var xs = [ 1, 2, 3, 4, 5, 6 ];
var ixes = [];
var ys = concatMap(xs, function (x, ix) {
ixes.push(ix);
return x % 2 ? [ x - 0.1, x, x + 0.1 ] : [];
});
t.same(ys, [ 0.9, 1, 1.1, 2.9, 3, 3.1, 4.9, 5, 5.1 ]);
t.same(ixes, [ 0, 1, 2, 3, 4, 5 ]);
t.end();
});
test('always something', function (t) {
var xs = [ 'a', 'b', 'c', 'd' ];
var ys = concatMap(xs, function (x) {
return x === 'b' ? [ 'B', 'B', 'B' ] : [ x ];
});
t.same(ys, [ 'a', 'B', 'B', 'B', 'c', 'd' ]);
t.end();
});
test('scalars', function (t) {
var xs = [ 'a', 'b', 'c', 'd' ];
var ys = concatMap(xs, function (x) {
return x === 'b' ? [ 'B', 'B', 'B' ] : x;
});
t.same(ys, [ 'a', 'B', 'B', 'B', 'c', 'd' ]);
t.end();
});
test('undefs', function (t) {
var xs = [ 'a', 'b', 'c', 'd' ];
var ys = concatMap(xs, function () {});
t.same(ys, [ undefined, undefined, undefined, undefined ]);
t.end();
});
-19
View File
@@ -1,19 +0,0 @@
Copyright Node.js contributors. All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to
deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
IN THE SOFTWARE.
@@ -1,3 +0,0 @@
# core-util-is
The `util.is*` functions introduced in Node v0.12.
-107
View File
@@ -1,107 +0,0 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
// NOTE: These type checking functions intentionally don't use `instanceof`
// because it is fragile and can be easily faked with `Object.create()`.
function isArray(arg) {
if (Array.isArray) {
return Array.isArray(arg);
}
return objectToString(arg) === '[object Array]';
}
exports.isArray = isArray;
function isBoolean(arg) {
return typeof arg === 'boolean';
}
exports.isBoolean = isBoolean;
function isNull(arg) {
return arg === null;
}
exports.isNull = isNull;
function isNullOrUndefined(arg) {
return arg == null;
}
exports.isNullOrUndefined = isNullOrUndefined;
function isNumber(arg) {
return typeof arg === 'number';
}
exports.isNumber = isNumber;
function isString(arg) {
return typeof arg === 'string';
}
exports.isString = isString;
function isSymbol(arg) {
return typeof arg === 'symbol';
}
exports.isSymbol = isSymbol;
function isUndefined(arg) {
return arg === void 0;
}
exports.isUndefined = isUndefined;
function isRegExp(re) {
return objectToString(re) === '[object RegExp]';
}
exports.isRegExp = isRegExp;
function isObject(arg) {
return typeof arg === 'object' && arg !== null;
}
exports.isObject = isObject;
function isDate(d) {
return objectToString(d) === '[object Date]';
}
exports.isDate = isDate;
function isError(e) {
return (objectToString(e) === '[object Error]' || e instanceof Error);
}
exports.isError = isError;
function isFunction(arg) {
return typeof arg === 'function';
}
exports.isFunction = isFunction;
function isPrimitive(arg) {
return arg === null ||
typeof arg === 'boolean' ||
typeof arg === 'number' ||
typeof arg === 'string' ||
typeof arg === 'symbol' || // ES6 symbol
typeof arg === 'undefined';
}
exports.isPrimitive = isPrimitive;
exports.isBuffer = require('buffer').Buffer.isBuffer;
function objectToString(o) {
return Object.prototype.toString.call(o);
}
@@ -1,38 +0,0 @@
{
"name": "core-util-is",
"version": "1.0.3",
"description": "The `util.is*` functions introduced in Node v0.12.",
"main": "lib/util.js",
"files": [
"lib"
],
"repository": {
"type": "git",
"url": "git://github.com/isaacs/core-util-is"
},
"keywords": [
"util",
"isBuffer",
"isArray",
"isNumber",
"isString",
"isRegExp",
"isThis",
"isThat",
"polyfill"
],
"author": "Isaac Z. Schlueter <i@izs.me> (http://blog.izs.me/)",
"license": "MIT",
"bugs": {
"url": "https://github.com/isaacs/core-util-is/issues"
},
"scripts": {
"test": "tap test.js",
"preversion": "npm test",
"postversion": "npm publish",
"prepublishOnly": "git push origin --follow-tags"
},
"devDependencies": {
"tap": "^15.0.9"
}
}
-26
View File
@@ -1,26 +0,0 @@
Copyright (c) 2013, Deoxxa Development
======================================
All rights reserved.
--------------------
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of Deoxxa Development nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY DEOXXA DEVELOPMENT ''AS IS'' AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL DEOXXA DEVELOPMENT BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-115
View File
@@ -1,115 +0,0 @@
# duplexer2 [![Build Status](https://travis-ci.org/deoxxa/duplexer2.svg?branch=master)](https://travis-ci.org/deoxxa/duplexer2) [![Coverage Status](https://coveralls.io/repos/deoxxa/duplexer2/badge.svg?branch=master&service=github)](https://coveralls.io/github/deoxxa/duplexer2?branch=master)
Like [duplexer](https://github.com/Raynos/duplexer) but using Streams3
```javascript
var stream = require("stream");
var duplexer2 = require("duplexer2");
var writable = new stream.Writable({objectMode: true}),
readable = new stream.Readable({objectMode: true});
writable._write = function _write(input, encoding, done) {
if (readable.push(input)) {
return done();
} else {
readable.once("drain", done);
}
};
readable._read = function _read(n) {
// no-op
};
// simulate the readable thing closing after a bit
writable.once("finish", function() {
setTimeout(function() {
readable.push(null);
}, 500);
});
var duplex = duplexer2(writable, readable);
duplex.on("data", function(e) {
console.log("got data", JSON.stringify(e));
});
duplex.on("finish", function() {
console.log("got finish event");
});
duplex.on("end", function() {
console.log("got end event");
});
duplex.write("oh, hi there", function() {
console.log("finished writing");
});
duplex.end(function() {
console.log("finished ending");
});
```
```
got data "oh, hi there"
finished writing
got finish event
finished ending
got end event
```
## Overview
This is a reimplementation of [duplexer](https://www.npmjs.com/package/duplexer) using the
Streams3 API which is standard in Node as of v4. Everything largely
works the same.
## Installation
[Available via `npm`](https://docs.npmjs.com/cli/install):
```
$ npm i duplexer2
```
## API
### duplexer2
Creates a new `DuplexWrapper` object, which is the actual class that implements
most of the fun stuff. All that fun stuff is hidden. DON'T LOOK.
```javascript
duplexer2([options], writable, readable)
```
```javascript
const duplex = duplexer2(new stream.Writable(), new stream.Readable());
```
Arguments
* __options__ - an object specifying the regular `stream.Duplex` options, as
well as the properties described below.
* __writable__ - a writable stream
* __readable__ - a readable stream
Options
* __bubbleErrors__ - a boolean value that specifies whether to bubble errors
from the underlying readable/writable streams. Default is `true`.
## License
3-clause BSD. [A copy](./LICENSE) is included with the source.
## Contact
* GitHub ([deoxxa](http://github.com/deoxxa))
* Twitter ([@deoxxa](http://twitter.com/deoxxa))
* Email ([deoxxa@fknsrs.biz](mailto:deoxxa@fknsrs.biz))
-76
View File
@@ -1,76 +0,0 @@
"use strict";
var stream = require("readable-stream");
function DuplexWrapper(options, writable, readable) {
if (typeof readable === "undefined") {
readable = writable;
writable = options;
options = null;
}
stream.Duplex.call(this, options);
if (typeof readable.read !== "function") {
readable = (new stream.Readable(options)).wrap(readable);
}
this._writable = writable;
this._readable = readable;
this._waiting = false;
var self = this;
writable.once("finish", function() {
self.end();
});
this.once("finish", function() {
writable.end();
});
readable.on("readable", function() {
if (self._waiting) {
self._waiting = false;
self._read();
}
});
readable.once("end", function() {
self.push(null);
});
if (!options || typeof options.bubbleErrors === "undefined" || options.bubbleErrors) {
writable.on("error", function(err) {
self.emit("error", err);
});
readable.on("error", function(err) {
self.emit("error", err);
});
}
}
DuplexWrapper.prototype = Object.create(stream.Duplex.prototype, {constructor: {value: DuplexWrapper}});
DuplexWrapper.prototype._write = function _write(input, encoding, done) {
this._writable.write(input, encoding, done);
};
DuplexWrapper.prototype._read = function _read() {
var buf;
var reads = 0;
while ((buf = this._readable.read()) !== null) {
this.push(buf);
reads++;
}
if (reads === 0) {
this._waiting = true;
}
};
module.exports = function duplex2(options, writable, readable) {
return new DuplexWrapper(options, writable, readable);
};
module.exports.DuplexWrapper = DuplexWrapper;
-28
View File
@@ -1,28 +0,0 @@
{
"name": "duplexer2",
"version": "0.1.4",
"description": "Like duplexer but using streams3",
"files": [
"index.js"
],
"scripts": {
"test": "mocha -R tap"
},
"repository": "deoxxa/duplexer2",
"keywords": [
"duplex",
"duplexer",
"stream",
"stream3",
"join",
"combine"
],
"author": "Conrad Pankoff <deoxxa@fknsrs.biz> (http://www.fknsrs.biz/)",
"license": "BSD-3-Clause",
"dependencies": {
"readable-stream": "^2.0.2"
},
"devDependencies": {
"mocha": "^2.2.5"
}
}
-43
View File
@@ -1,43 +0,0 @@
The ISC License
Copyright (c) Isaac Z. Schlueter and Contributors
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
----
This library bundles a version of the `fs.realpath` and `fs.realpathSync`
methods from Node.js v0.10 under the terms of the Node.js MIT license.
Node's license follows, also included at the header of `old.js` which contains
the licensed code:
Copyright Joyent, Inc. and other Node contributors.
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
-33
View File
@@ -1,33 +0,0 @@
# fs.realpath
A backwards-compatible fs.realpath for Node v6 and above
In Node v6, the JavaScript implementation of fs.realpath was replaced
with a faster (but less resilient) native implementation. That raises
new and platform-specific errors and cannot handle long or excessively
symlink-looping paths.
This module handles those cases by detecting the new errors and
falling back to the JavaScript implementation. On versions of Node
prior to v6, it has no effect.
## USAGE
```js
var rp = require('fs.realpath')
// async version
rp.realpath(someLongAndLoopingPath, function (er, real) {
// the ELOOP was handled, but it was a bit slower
})
// sync version
var real = rp.realpathSync(someLongAndLoopingPath)
// monkeypatch at your own risk!
// This replaces the fs.realpath/fs.realpathSync builtins
rp.monkeypatch()
// un-do the monkeypatching
rp.unmonkeypatch()
```
-66
View File
@@ -1,66 +0,0 @@
module.exports = realpath
realpath.realpath = realpath
realpath.sync = realpathSync
realpath.realpathSync = realpathSync
realpath.monkeypatch = monkeypatch
realpath.unmonkeypatch = unmonkeypatch
var fs = require('fs')
var origRealpath = fs.realpath
var origRealpathSync = fs.realpathSync
var version = process.version
var ok = /^v[0-5]\./.test(version)
var old = require('./old.js')
function newError (er) {
return er && er.syscall === 'realpath' && (
er.code === 'ELOOP' ||
er.code === 'ENOMEM' ||
er.code === 'ENAMETOOLONG'
)
}
function realpath (p, cache, cb) {
if (ok) {
return origRealpath(p, cache, cb)
}
if (typeof cache === 'function') {
cb = cache
cache = null
}
origRealpath(p, cache, function (er, result) {
if (newError(er)) {
old.realpath(p, cache, cb)
} else {
cb(er, result)
}
})
}
function realpathSync (p, cache) {
if (ok) {
return origRealpathSync(p, cache)
}
try {
return origRealpathSync(p, cache)
} catch (er) {
if (newError(er)) {
return old.realpathSync(p, cache)
} else {
throw er
}
}
}
function monkeypatch () {
fs.realpath = realpath
fs.realpathSync = realpathSync
}
function unmonkeypatch () {
fs.realpath = origRealpath
fs.realpathSync = origRealpathSync
}
-303
View File
@@ -1,303 +0,0 @@
// Copyright Joyent, Inc. and other Node contributors.
//
// Permission is hereby granted, free of charge, to any person obtaining a
// copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to permit
// persons to whom the Software is furnished to do so, subject to the
// following conditions:
//
// The above copyright notice and this permission notice shall be included
// in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
// USE OR OTHER DEALINGS IN THE SOFTWARE.
var pathModule = require('path');
var isWindows = process.platform === 'win32';
var fs = require('fs');
// JavaScript implementation of realpath, ported from node pre-v6
var DEBUG = process.env.NODE_DEBUG && /fs/.test(process.env.NODE_DEBUG);
function rethrow() {
// Only enable in debug mode. A backtrace uses ~1000 bytes of heap space and
// is fairly slow to generate.
var callback;
if (DEBUG) {
var backtrace = new Error;
callback = debugCallback;
} else
callback = missingCallback;
return callback;
function debugCallback(err) {
if (err) {
backtrace.message = err.message;
err = backtrace;
missingCallback(err);
}
}
function missingCallback(err) {
if (err) {
if (process.throwDeprecation)
throw err; // Forgot a callback but don't know where? Use NODE_DEBUG=fs
else if (!process.noDeprecation) {
var msg = 'fs: missing callback ' + (err.stack || err.message);
if (process.traceDeprecation)
console.trace(msg);
else
console.error(msg);
}
}
}
}
function maybeCallback(cb) {
return typeof cb === 'function' ? cb : rethrow();
}
var normalize = pathModule.normalize;
// Regexp that finds the next partion of a (partial) path
// result is [base_with_slash, base], e.g. ['somedir/', 'somedir']
if (isWindows) {
var nextPartRe = /(.*?)(?:[\/\\]+|$)/g;
} else {
var nextPartRe = /(.*?)(?:[\/]+|$)/g;
}
// Regex to find the device root, including trailing slash. E.g. 'c:\\'.
if (isWindows) {
var splitRootRe = /^(?:[a-zA-Z]:|[\\\/]{2}[^\\\/]+[\\\/][^\\\/]+)?[\\\/]*/;
} else {
var splitRootRe = /^[\/]*/;
}
exports.realpathSync = function realpathSync(p, cache) {
// make p is absolute
p = pathModule.resolve(p);
if (cache && Object.prototype.hasOwnProperty.call(cache, p)) {
return cache[p];
}
var original = p,
seenLinks = {},
knownHard = {};
// current character position in p
var pos;
// the partial path so far, including a trailing slash if any
var current;
// the partial path without a trailing slash (except when pointing at a root)
var base;
// the partial path scanned in the previous round, with slash
var previous;
start();
function start() {
// Skip over roots
var m = splitRootRe.exec(p);
pos = m[0].length;
current = m[0];
base = m[0];
previous = '';
// On windows, check that the root exists. On unix there is no need.
if (isWindows && !knownHard[base]) {
fs.lstatSync(base);
knownHard[base] = true;
}
}
// walk down the path, swapping out linked pathparts for their real
// values
// NB: p.length changes.
while (pos < p.length) {
// find the next part
nextPartRe.lastIndex = pos;
var result = nextPartRe.exec(p);
previous = current;
current += result[0];
base = previous + result[1];
pos = nextPartRe.lastIndex;
// continue if not a symlink
if (knownHard[base] || (cache && cache[base] === base)) {
continue;
}
var resolvedLink;
if (cache && Object.prototype.hasOwnProperty.call(cache, base)) {
// some known symbolic link. no need to stat again.
resolvedLink = cache[base];
} else {
var stat = fs.lstatSync(base);
if (!stat.isSymbolicLink()) {
knownHard[base] = true;
if (cache) cache[base] = base;
continue;
}
// read the link if it wasn't read before
// dev/ino always return 0 on windows, so skip the check.
var linkTarget = null;
if (!isWindows) {
var id = stat.dev.toString(32) + ':' + stat.ino.toString(32);
if (seenLinks.hasOwnProperty(id)) {
linkTarget = seenLinks[id];
}
}
if (linkTarget === null) {
fs.statSync(base);
linkTarget = fs.readlinkSync(base);
}
resolvedLink = pathModule.resolve(previous, linkTarget);
// track this, if given a cache.
if (cache) cache[base] = resolvedLink;
if (!isWindows) seenLinks[id] = linkTarget;
}
// resolve the link, then start over
p = pathModule.resolve(resolvedLink, p.slice(pos));
start();
}
if (cache) cache[original] = p;
return p;
};
exports.realpath = function realpath(p, cache, cb) {
if (typeof cb !== 'function') {
cb = maybeCallback(cache);
cache = null;
}
// make p is absolute
p = pathModule.resolve(p);
if (cache && Object.prototype.hasOwnProperty.call(cache, p)) {
return process.nextTick(cb.bind(null, null, cache[p]));
}
var original = p,
seenLinks = {},
knownHard = {};
// current character position in p
var pos;
// the partial path so far, including a trailing slash if any
var current;
// the partial path without a trailing slash (except when pointing at a root)
var base;
// the partial path scanned in the previous round, with slash
var previous;
start();
function start() {
// Skip over roots
var m = splitRootRe.exec(p);
pos = m[0].length;
current = m[0];
base = m[0];
previous = '';
// On windows, check that the root exists. On unix there is no need.
if (isWindows && !knownHard[base]) {
fs.lstat(base, function(err) {
if (err) return cb(err);
knownHard[base] = true;
LOOP();
});
} else {
process.nextTick(LOOP);
}
}
// walk down the path, swapping out linked pathparts for their real
// values
function LOOP() {
// stop if scanned past end of path
if (pos >= p.length) {
if (cache) cache[original] = p;
return cb(null, p);
}
// find the next part
nextPartRe.lastIndex = pos;
var result = nextPartRe.exec(p);
previous = current;
current += result[0];
base = previous + result[1];
pos = nextPartRe.lastIndex;
// continue if not a symlink
if (knownHard[base] || (cache && cache[base] === base)) {
return process.nextTick(LOOP);
}
if (cache && Object.prototype.hasOwnProperty.call(cache, base)) {
// known symbolic link. no need to stat again.
return gotResolvedLink(cache[base]);
}
return fs.lstat(base, gotStat);
}
function gotStat(err, stat) {
if (err) return cb(err);
// if not a symlink, skip to the next path part
if (!stat.isSymbolicLink()) {
knownHard[base] = true;
if (cache) cache[base] = base;
return process.nextTick(LOOP);
}
// stat & read the link if not read before
// call gotTarget as soon as the link target is known
// dev/ino always return 0 on windows, so skip the check.
if (!isWindows) {
var id = stat.dev.toString(32) + ':' + stat.ino.toString(32);
if (seenLinks.hasOwnProperty(id)) {
return gotTarget(null, seenLinks[id], base);
}
}
fs.stat(base, function(err) {
if (err) return cb(err);
fs.readlink(base, function(err, target) {
if (!isWindows) seenLinks[id] = target;
gotTarget(err, target);
});
});
}
function gotTarget(err, target, base) {
if (err) return cb(err);
var resolvedLink = pathModule.resolve(previous, target);
if (cache) cache[base] = resolvedLink;
gotResolvedLink(resolvedLink);
}
function gotResolvedLink(resolvedLink) {
// resolve the link, then start over
p = pathModule.resolve(resolvedLink, p.slice(pos));
start();
}
};
@@ -1,26 +0,0 @@
{
"name": "fs.realpath",
"version": "1.0.0",
"description": "Use node's fs.realpath, but fall back to the JS implementation if the native one fails",
"main": "index.js",
"dependencies": {},
"devDependencies": {},
"scripts": {
"test": "tap test/*.js --cov"
},
"repository": {
"type": "git",
"url": "git+https://github.com/isaacs/fs.realpath.git"
},
"keywords": [
"realpath",
"fs",
"polyfill"
],
"author": "Isaac Z. Schlueter <i@izs.me> (http://blog.izs.me/)",
"license": "ISC",
"files": [
"old.js",
"index.js"
]
}
-9
View File
@@ -1,9 +0,0 @@
language: node_js
node_js:
- "6"
- "4"
- "0.10"
- "0.12"
before_install:
- "npm config set spin false"
- "npm install -g npm/npm"
-15
View File
@@ -1,15 +0,0 @@
The ISC License
Copyright (c) Isaac Z. Schlueter and Contributors
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-76
View File
@@ -1,76 +0,0 @@
Like FS streams, but with stat on them, and supporting directories and
symbolic links, as well as normal files. Also, you can use this to set
the stats on a file, even if you don't change its contents, or to create
a symlink, etc.
So, for example, you can "write" a directory, and it'll call `mkdir`. You
can specify a uid and gid, and it'll call `chown`. You can specify a
`mtime` and `atime`, and it'll call `utimes`. You can call it a symlink
and provide a `linkpath` and it'll call `symlink`.
Note that it won't automatically resolve symbolic links. So, if you
call `fstream.Reader('/some/symlink')` then you'll get an object
that stats and then ends immediately (since it has no data). To follow
symbolic links, do this: `fstream.Reader({path:'/some/symlink', follow:
true })`.
There are various checks to make sure that the bytes emitted are the
same as the intended size, if the size is set.
## Examples
```javascript
fstream
.Writer({ path: "path/to/file"
, mode: 0755
, size: 6
})
.write("hello\n")
.end()
```
This will create the directories if they're missing, and then write
`hello\n` into the file, chmod it to 0755, and assert that 6 bytes have
been written when it's done.
```javascript
fstream
.Writer({ path: "path/to/file"
, mode: 0755
, size: 6
, flags: "a"
})
.write("hello\n")
.end()
```
You can pass flags in, if you want to append to a file.
```javascript
fstream
.Writer({ path: "path/to/symlink"
, linkpath: "./file"
, SymbolicLink: true
, mode: "0755" // octal strings supported
})
.end()
```
If isSymbolicLink is a function, it'll be called, and if it returns
true, then it'll treat it as a symlink. If it's not a function, then
any truish value will make a symlink, or you can set `type:
'SymbolicLink'`, which does the same thing.
Note that the linkpath is relative to the symbolic link location, not
the parent dir or cwd.
```javascript
fstream
.Reader("path/to/dir")
.pipe(fstream.Writer("path/to/other/dir"))
```
This will do like `cp -Rp path/to/dir path/to/other/dir`. If the other
dir exists and isn't a directory, then it'll emit an error. It'll also
set the uid, gid, mode, etc. to be identical. In this way, it's more
like `rsync -a` than simply a copy.
@@ -1,134 +0,0 @@
var fstream = require('../fstream.js')
var path = require('path')
var r = fstream.Reader({
path: path.dirname(__dirname),
filter: function () {
return !this.basename.match(/^\./) &&
!this.basename.match(/^node_modules$/) &&
!this.basename.match(/^deep-copy$/) &&
!this.basename.match(/^filter-copy$/)
}
})
// this writer will only write directories
var w = fstream.Writer({
path: path.resolve(__dirname, 'filter-copy'),
type: 'Directory',
filter: function () {
return this.type === 'Directory'
}
})
var indent = ''
r.on('entry', appears)
r.on('ready', function () {
console.error('ready to begin!', r.path)
})
function appears (entry) {
console.error(indent + 'a %s appears!', entry.type, entry.basename, typeof entry.basename)
if (foggy) {
console.error('FOGGY!')
var p = entry
do {
console.error(p.depth, p.path, p._paused)
p = p.parent
} while (p)
throw new Error('\u001b[mshould not have entries while foggy')
}
indent += '\t'
entry.on('data', missile(entry))
entry.on('end', runaway(entry))
entry.on('entry', appears)
}
var foggy
function missile (entry) {
function liftFog (who) {
if (!foggy) return
if (who) {
console.error('%s breaks the spell!', who && who.path)
} else {
console.error('the spell expires!')
}
console.error('\u001b[mthe fog lifts!\n')
clearTimeout(foggy)
foggy = null
if (entry._paused) entry.resume()
}
if (entry.type === 'Directory') {
var ended = false
entry.once('end', function () { ended = true })
return function (c) {
// throw in some pathological pause()/resume() behavior
// just for extra fun.
process.nextTick(function () {
if (!foggy && !ended) { // && Math.random() < 0.3) {
console.error(indent + '%s casts a spell', entry.basename)
console.error('\na slowing fog comes over the battlefield...\n\u001b[32m')
entry.pause()
entry.once('resume', liftFog)
foggy = setTimeout(liftFog, 1000)
}
})
}
}
return function (c) {
var e = Math.random() < 0.5
console.error(indent + '%s %s for %d damage!',
entry.basename,
e ? 'is struck' : 'fires a chunk',
c.length)
}
}
function runaway (entry) {
return function () {
var e = Math.random() < 0.5
console.error(indent + '%s %s',
entry.basename,
e ? 'turns to flee' : 'is vanquished!')
indent = indent.slice(0, -1)
}
}
w.on('entry', attacks)
// w.on('ready', function () { attacks(w) })
function attacks (entry) {
console.error(indent + '%s %s!', entry.basename,
entry.type === 'Directory' ? 'calls for backup' : 'attacks')
entry.on('entry', attacks)
}
var ended = false
var i = 1
r.on('end', function () {
if (foggy) clearTimeout(foggy)
console.error("\u001b[mIT'S OVER!!")
console.error('A WINNAR IS YOU!')
console.log('ok ' + (i++) + ' A WINNAR IS YOU')
ended = true
// now go through and verify that everything in there is a dir.
var p = path.resolve(__dirname, 'filter-copy')
var checker = fstream.Reader({ path: p })
checker.checker = true
checker.on('child', function (e) {
var ok = e.type === 'Directory'
console.log((ok ? '' : 'not ') + 'ok ' + (i++) +
' should be a dir: ' +
e.path.substr(checker.path.length + 1))
})
})
process.on('exit', function () {
console.log((ended ? '' : 'not ') + 'ok ' + (i) + ' ended')
console.log('1..' + i)
})
r.pipe(w)
-118
View File
@@ -1,118 +0,0 @@
var fstream = require('../fstream.js')
var path = require('path')
var r = fstream.Reader({
path: path.dirname(__dirname),
filter: function () {
return !this.basename.match(/^\./) &&
!this.basename.match(/^node_modules$/) &&
!this.basename.match(/^deep-copy$/)
}
})
var w = fstream.Writer({
path: path.resolve(__dirname, 'deep-copy'),
type: 'Directory'
})
var indent = ''
r.on('entry', appears)
r.on('ready', function () {
console.error('ready to begin!', r.path)
})
function appears (entry) {
console.error(indent + 'a %s appears!', entry.type, entry.basename, typeof entry.basename, entry)
if (foggy) {
console.error('FOGGY!')
var p = entry
do {
console.error(p.depth, p.path, p._paused)
p = p.parent
} while (p)
throw new Error('\u001b[mshould not have entries while foggy')
}
indent += '\t'
entry.on('data', missile(entry))
entry.on('end', runaway(entry))
entry.on('entry', appears)
}
var foggy
function missile (entry) {
function liftFog (who) {
if (!foggy) return
if (who) {
console.error('%s breaks the spell!', who && who.path)
} else {
console.error('the spell expires!')
}
console.error('\u001b[mthe fog lifts!\n')
clearTimeout(foggy)
foggy = null
if (entry._paused) entry.resume()
}
if (entry.type === 'Directory') {
var ended = false
entry.once('end', function () { ended = true })
return function (c) {
// throw in some pathological pause()/resume() behavior
// just for extra fun.
process.nextTick(function () {
if (!foggy && !ended) { // && Math.random() < 0.3) {
console.error(indent + '%s casts a spell', entry.basename)
console.error('\na slowing fog comes over the battlefield...\n\u001b[32m')
entry.pause()
entry.once('resume', liftFog)
foggy = setTimeout(liftFog, 10)
}
})
}
}
return function (c) {
var e = Math.random() < 0.5
console.error(indent + '%s %s for %d damage!',
entry.basename,
e ? 'is struck' : 'fires a chunk',
c.length)
}
}
function runaway (entry) {
return function () {
var e = Math.random() < 0.5
console.error(indent + '%s %s',
entry.basename,
e ? 'turns to flee' : 'is vanquished!')
indent = indent.slice(0, -1)
}
}
w.on('entry', attacks)
// w.on('ready', function () { attacks(w) })
function attacks (entry) {
console.error(indent + '%s %s!', entry.basename,
entry.type === 'Directory' ? 'calls for backup' : 'attacks')
entry.on('entry', attacks)
}
var ended = false
r.on('end', function () {
if (foggy) clearTimeout(foggy)
console.error("\u001b[mIT'S OVER!!")
console.error('A WINNAR IS YOU!')
console.log('ok 1 A WINNAR IS YOU')
ended = true
})
process.on('exit', function () {
console.log((ended ? '' : 'not ') + 'ok 2 ended')
console.log('1..2')
})
r.pipe(w)
@@ -1,68 +0,0 @@
var fstream = require('../fstream.js')
var tap = require('tap')
var fs = require('fs')
var path = require('path')
var dir = path.dirname(__dirname)
tap.test('reader test', function (t) {
var children = -1
var gotReady = false
var ended = false
var r = fstream.Reader({
path: dir,
filter: function () {
// return this.parent === r
return this.parent === r || this === r
}
})
r.on('ready', function () {
gotReady = true
children = fs.readdirSync(dir).length
console.error('Setting expected children to ' + children)
t.equal(r.type, 'Directory', 'should be a directory')
})
r.on('entry', function (entry) {
children--
if (!gotReady) {
t.fail('children before ready!')
}
t.equal(entry.dirname, r.path, 'basename is parent dir')
})
r.on('error', function (er) {
t.fail(er)
t.end()
process.exit(1)
})
r.on('end', function () {
t.equal(children, 0, 'should have seen all children')
ended = true
})
var closed = false
r.on('close', function () {
t.ok(ended, 'saw end before close')
t.notOk(closed, 'close should only happen once')
closed = true
t.end()
})
})
tap.test('reader error test', function (t) {
// assumes non-root on a *nix system
var r = fstream.Reader({ path: '/etc/shadow' })
r.once('error', function (er) {
t.ok(true)
t.end()
})
r.on('end', function () {
t.fail('reader ended without error')
t.end()
})
})
@@ -1,27 +0,0 @@
var fstream = require('../fstream.js')
var notOpen = false
process.chdir(__dirname)
fstream
.Writer({
path: 'path/to/symlink',
linkpath: './file',
isSymbolicLink: true,
mode: '0755' // octal strings supported
})
.on('close', function () {
notOpen = true
var fs = require('fs')
var s = fs.lstatSync('path/to/symlink')
var isSym = s.isSymbolicLink()
console.log((isSym ? '' : 'not ') + 'ok 1 should be symlink')
var t = fs.readlinkSync('path/to/symlink')
var isTarget = t === './file'
console.log((isTarget ? '' : 'not ') + 'ok 2 should link to ./file')
})
.end()
process.on('exit', function () {
console.log((notOpen ? '' : 'not ') + 'ok 3 should be closed')
console.log('1..3')
})
-35
View File
@@ -1,35 +0,0 @@
exports.Abstract = require('./lib/abstract.js')
exports.Reader = require('./lib/reader.js')
exports.Writer = require('./lib/writer.js')
exports.File = {
Reader: require('./lib/file-reader.js'),
Writer: require('./lib/file-writer.js')
}
exports.Dir = {
Reader: require('./lib/dir-reader.js'),
Writer: require('./lib/dir-writer.js')
}
exports.Link = {
Reader: require('./lib/link-reader.js'),
Writer: require('./lib/link-writer.js')
}
exports.Proxy = {
Reader: require('./lib/proxy-reader.js'),
Writer: require('./lib/proxy-writer.js')
}
exports.Reader.Dir = exports.DirReader = exports.Dir.Reader
exports.Reader.File = exports.FileReader = exports.File.Reader
exports.Reader.Link = exports.LinkReader = exports.Link.Reader
exports.Reader.Proxy = exports.ProxyReader = exports.Proxy.Reader
exports.Writer.Dir = exports.DirWriter = exports.Dir.Writer
exports.Writer.File = exports.FileWriter = exports.File.Writer
exports.Writer.Link = exports.LinkWriter = exports.Link.Writer
exports.Writer.Proxy = exports.ProxyWriter = exports.Proxy.Writer
exports.collect = require('./lib/collect.js')
-85
View File
@@ -1,85 +0,0 @@
// the parent class for all fstreams.
module.exports = Abstract
var Stream = require('stream').Stream
var inherits = require('inherits')
function Abstract () {
Stream.call(this)
}
inherits(Abstract, Stream)
Abstract.prototype.on = function (ev, fn) {
if (ev === 'ready' && this.ready) {
process.nextTick(fn.bind(this))
} else {
Stream.prototype.on.call(this, ev, fn)
}
return this
}
Abstract.prototype.abort = function () {
this._aborted = true
this.emit('abort')
}
Abstract.prototype.destroy = function () {}
Abstract.prototype.warn = function (msg, code) {
var self = this
var er = decorate(msg, code, self)
if (!self.listeners('warn')) {
console.error('%s %s\n' +
'path = %s\n' +
'syscall = %s\n' +
'fstream_type = %s\n' +
'fstream_path = %s\n' +
'fstream_unc_path = %s\n' +
'fstream_class = %s\n' +
'fstream_stack =\n%s\n',
code || 'UNKNOWN',
er.stack,
er.path,
er.syscall,
er.fstream_type,
er.fstream_path,
er.fstream_unc_path,
er.fstream_class,
er.fstream_stack.join('\n'))
} else {
self.emit('warn', er)
}
}
Abstract.prototype.info = function (msg, code) {
this.emit('info', msg, code)
}
Abstract.prototype.error = function (msg, code, th) {
var er = decorate(msg, code, this)
if (th) throw er
else this.emit('error', er)
}
function decorate (er, code, self) {
if (!(er instanceof Error)) er = new Error(er)
er.code = er.code || code
er.path = er.path || self.path
er.fstream_type = er.fstream_type || self.type
er.fstream_path = er.fstream_path || self.path
if (self._path !== self.path) {
er.fstream_unc_path = er.fstream_unc_path || self._path
}
if (self.linkpath) {
er.fstream_linkpath = er.fstream_linkpath || self.linkpath
}
er.fstream_class = er.fstream_class || self.constructor.name
er.fstream_stack = er.fstream_stack ||
new Error().stack.split(/\n/).slice(3).map(function (s) {
return s.replace(/^ {4}at /, '')
})
return er
}
-70
View File
@@ -1,70 +0,0 @@
module.exports = collect
function collect (stream) {
if (stream._collected) return
if (stream._paused) return stream.on('resume', collect.bind(null, stream))
stream._collected = true
stream.pause()
stream.on('data', save)
stream.on('end', save)
var buf = []
function save (b) {
if (typeof b === 'string') b = new Buffer(b)
if (Buffer.isBuffer(b) && !b.length) return
buf.push(b)
}
stream.on('entry', saveEntry)
var entryBuffer = []
function saveEntry (e) {
collect(e)
entryBuffer.push(e)
}
stream.on('proxy', proxyPause)
function proxyPause (p) {
p.pause()
}
// replace the pipe method with a new version that will
// unlock the buffered stuff. if you just call .pipe()
// without a destination, then it'll re-play the events.
stream.pipe = (function (orig) {
return function (dest) {
// console.error(' === open the pipes', dest && dest.path)
// let the entries flow through one at a time.
// Once they're all done, then we can resume completely.
var e = 0
;(function unblockEntry () {
var entry = entryBuffer[e++]
// console.error(" ==== unblock entry", entry && entry.path)
if (!entry) return resume()
entry.on('end', unblockEntry)
if (dest) dest.add(entry)
else stream.emit('entry', entry)
})()
function resume () {
stream.removeListener('entry', saveEntry)
stream.removeListener('data', save)
stream.removeListener('end', save)
stream.pipe = orig
if (dest) stream.pipe(dest)
buf.forEach(function (b) {
if (b) stream.emit('data', b)
else stream.emit('end')
})
stream.resume()
}
return dest
}
})(stream.pipe)
}
@@ -1,252 +0,0 @@
// A thing that emits "entry" events with Reader objects
// Pausing it causes it to stop emitting entry events, and also
// pauses the current entry if there is one.
module.exports = DirReader
var fs = require('graceful-fs')
var inherits = require('inherits')
var path = require('path')
var Reader = require('./reader.js')
var assert = require('assert').ok
inherits(DirReader, Reader)
function DirReader (props) {
var self = this
if (!(self instanceof DirReader)) {
throw new Error('DirReader must be called as constructor.')
}
// should already be established as a Directory type
if (props.type !== 'Directory' || !props.Directory) {
throw new Error('Non-directory type ' + props.type)
}
self.entries = null
self._index = -1
self._paused = false
self._length = -1
if (props.sort) {
this.sort = props.sort
}
Reader.call(this, props)
}
DirReader.prototype._getEntries = function () {
var self = this
// race condition. might pause() before calling _getEntries,
// and then resume, and try to get them a second time.
if (self._gotEntries) return
self._gotEntries = true
fs.readdir(self._path, function (er, entries) {
if (er) return self.error(er)
self.entries = entries
self.emit('entries', entries)
if (self._paused) self.once('resume', processEntries)
else processEntries()
function processEntries () {
self._length = self.entries.length
if (typeof self.sort === 'function') {
self.entries = self.entries.sort(self.sort.bind(self))
}
self._read()
}
})
}
// start walking the dir, and emit an "entry" event for each one.
DirReader.prototype._read = function () {
var self = this
if (!self.entries) return self._getEntries()
if (self._paused || self._currentEntry || self._aborted) {
// console.error('DR paused=%j, current=%j, aborted=%j', self._paused, !!self._currentEntry, self._aborted)
return
}
self._index++
if (self._index >= self.entries.length) {
if (!self._ended) {
self._ended = true
self.emit('end')
self.emit('close')
}
return
}
// ok, handle this one, then.
// save creating a proxy, by stat'ing the thing now.
var p = path.resolve(self._path, self.entries[self._index])
assert(p !== self._path)
assert(self.entries[self._index])
// set this to prevent trying to _read() again in the stat time.
self._currentEntry = p
fs[ self.props.follow ? 'stat' : 'lstat' ](p, function (er, stat) {
if (er) return self.error(er)
var who = self._proxy || self
stat.path = p
stat.basename = path.basename(p)
stat.dirname = path.dirname(p)
var childProps = self.getChildProps.call(who, stat)
childProps.path = p
childProps.basename = path.basename(p)
childProps.dirname = path.dirname(p)
var entry = Reader(childProps, stat)
// console.error("DR Entry", p, stat.size)
self._currentEntry = entry
// "entry" events are for direct entries in a specific dir.
// "child" events are for any and all children at all levels.
// This nomenclature is not completely final.
entry.on('pause', function (who) {
if (!self._paused && !entry._disowned) {
self.pause(who)
}
})
entry.on('resume', function (who) {
if (self._paused && !entry._disowned) {
self.resume(who)
}
})
entry.on('stat', function (props) {
self.emit('_entryStat', entry, props)
if (entry._aborted) return
if (entry._paused) {
entry.once('resume', function () {
self.emit('entryStat', entry, props)
})
} else self.emit('entryStat', entry, props)
})
entry.on('ready', function EMITCHILD () {
// console.error("DR emit child", entry._path)
if (self._paused) {
// console.error(" DR emit child - try again later")
// pause the child, and emit the "entry" event once we drain.
// console.error("DR pausing child entry")
entry.pause(self)
return self.once('resume', EMITCHILD)
}
// skip over sockets. they can't be piped around properly,
// so there's really no sense even acknowledging them.
// if someone really wants to see them, they can listen to
// the "socket" events.
if (entry.type === 'Socket') {
self.emit('socket', entry)
} else {
self.emitEntry(entry)
}
})
var ended = false
entry.on('close', onend)
entry.on('disown', onend)
function onend () {
if (ended) return
ended = true
self.emit('childEnd', entry)
self.emit('entryEnd', entry)
self._currentEntry = null
if (!self._paused) {
self._read()
}
}
// XXX Remove this. Works in node as of 0.6.2 or so.
// Long filenames should not break stuff.
entry.on('error', function (er) {
if (entry._swallowErrors) {
self.warn(er)
entry.emit('end')
entry.emit('close')
} else {
self.emit('error', er)
}
})
// proxy up some events.
;[
'child',
'childEnd',
'warn'
].forEach(function (ev) {
entry.on(ev, self.emit.bind(self, ev))
})
})
}
DirReader.prototype.disown = function (entry) {
entry.emit('beforeDisown')
entry._disowned = true
entry.parent = entry.root = null
if (entry === this._currentEntry) {
this._currentEntry = null
}
entry.emit('disown')
}
DirReader.prototype.getChildProps = function () {
return {
depth: this.depth + 1,
root: this.root || this,
parent: this,
follow: this.follow,
filter: this.filter,
sort: this.props.sort,
hardlinks: this.props.hardlinks
}
}
DirReader.prototype.pause = function (who) {
var self = this
if (self._paused) return
who = who || self
self._paused = true
if (self._currentEntry && self._currentEntry.pause) {
self._currentEntry.pause(who)
}
self.emit('pause', who)
}
DirReader.prototype.resume = function (who) {
var self = this
if (!self._paused) return
who = who || self
self._paused = false
// console.error('DR Emit Resume', self._path)
self.emit('resume', who)
if (self._paused) {
// console.error('DR Re-paused', self._path)
return
}
if (self._currentEntry) {
if (self._currentEntry.resume) self._currentEntry.resume(who)
} else self._read()
}
DirReader.prototype.emitEntry = function (entry) {
this.emit('entry', entry)
this.emit('child', entry)
}
@@ -1,174 +0,0 @@
// It is expected that, when .add() returns false, the consumer
// of the DirWriter will pause until a "drain" event occurs. Note
// that this is *almost always going to be the case*, unless the
// thing being written is some sort of unsupported type, and thus
// skipped over.
module.exports = DirWriter
var Writer = require('./writer.js')
var inherits = require('inherits')
var mkdir = require('mkdirp')
var path = require('path')
var collect = require('./collect.js')
inherits(DirWriter, Writer)
function DirWriter (props) {
var self = this
if (!(self instanceof DirWriter)) {
self.error('DirWriter must be called as constructor.', null, true)
}
// should already be established as a Directory type
if (props.type !== 'Directory' || !props.Directory) {
self.error('Non-directory type ' + props.type + ' ' +
JSON.stringify(props), null, true)
}
Writer.call(this, props)
}
DirWriter.prototype._create = function () {
var self = this
mkdir(self._path, Writer.dirmode, function (er) {
if (er) return self.error(er)
// ready to start getting entries!
self.ready = true
self.emit('ready')
self._process()
})
}
// a DirWriter has an add(entry) method, but its .write() doesn't
// do anything. Why a no-op rather than a throw? Because this
// leaves open the door for writing directory metadata for
// gnu/solaris style dumpdirs.
DirWriter.prototype.write = function () {
return true
}
DirWriter.prototype.end = function () {
this._ended = true
this._process()
}
DirWriter.prototype.add = function (entry) {
var self = this
// console.error('\tadd', entry._path, '->', self._path)
collect(entry)
if (!self.ready || self._currentEntry) {
self._buffer.push(entry)
return false
}
// create a new writer, and pipe the incoming entry into it.
if (self._ended) {
return self.error('add after end')
}
self._buffer.push(entry)
self._process()
return this._buffer.length === 0
}
DirWriter.prototype._process = function () {
var self = this
// console.error('DW Process p=%j', self._processing, self.basename)
if (self._processing) return
var entry = self._buffer.shift()
if (!entry) {
// console.error("DW Drain")
self.emit('drain')
if (self._ended) self._finish()
return
}
self._processing = true
// console.error("DW Entry", entry._path)
self.emit('entry', entry)
// ok, add this entry
//
// don't allow recursive copying
var p = entry
var pp
do {
pp = p._path || p.path
if (pp === self.root._path || pp === self._path ||
(pp && pp.indexOf(self._path) === 0)) {
// console.error('DW Exit (recursive)', entry.basename, self._path)
self._processing = false
if (entry._collected) entry.pipe()
return self._process()
}
p = p.parent
} while (p)
// console.error("DW not recursive")
// chop off the entry's root dir, replace with ours
var props = {
parent: self,
root: self.root || self,
type: entry.type,
depth: self.depth + 1
}
pp = entry._path || entry.path || entry.props.path
if (entry.parent) {
pp = pp.substr(entry.parent._path.length + 1)
}
// get rid of any ../../ shenanigans
props.path = path.join(self.path, path.join('/', pp))
// if i have a filter, the child should inherit it.
props.filter = self.filter
// all the rest of the stuff, copy over from the source.
Object.keys(entry.props).forEach(function (k) {
if (!props.hasOwnProperty(k)) {
props[k] = entry.props[k]
}
})
// not sure at this point what kind of writer this is.
var child = self._currentChild = new Writer(props)
child.on('ready', function () {
// console.error("DW Child Ready", child.type, child._path)
// console.error(" resuming", entry._path)
entry.pipe(child)
entry.resume()
})
// XXX Make this work in node.
// Long filenames should not break stuff.
child.on('error', function (er) {
if (child._swallowErrors) {
self.warn(er)
child.emit('end')
child.emit('close')
} else {
self.emit('error', er)
}
})
// we fire _end internally *after* end, so that we don't move on
// until any "end" listeners have had their chance to do stuff.
child.on('close', onend)
var ended = false
function onend () {
if (ended) return
ended = true
// console.error("* DW Child end", child.basename)
self._currentChild = null
self._processing = false
self._process()
}
}
@@ -1,150 +0,0 @@
// Basically just a wrapper around an fs.ReadStream
module.exports = FileReader
var fs = require('graceful-fs')
var inherits = require('inherits')
var Reader = require('./reader.js')
var EOF = {EOF: true}
var CLOSE = {CLOSE: true}
inherits(FileReader, Reader)
function FileReader (props) {
// console.error(" FR create", props.path, props.size, new Error().stack)
var self = this
if (!(self instanceof FileReader)) {
throw new Error('FileReader must be called as constructor.')
}
// should already be established as a File type
// XXX Todo: preserve hardlinks by tracking dev+inode+nlink,
// with a HardLinkReader class.
if (!((props.type === 'Link' && props.Link) ||
(props.type === 'File' && props.File))) {
throw new Error('Non-file type ' + props.type)
}
self._buffer = []
self._bytesEmitted = 0
Reader.call(self, props)
}
FileReader.prototype._getStream = function () {
var self = this
var stream = self._stream = fs.createReadStream(self._path, self.props)
if (self.props.blksize) {
stream.bufferSize = self.props.blksize
}
stream.on('open', self.emit.bind(self, 'open'))
stream.on('data', function (c) {
// console.error('\t\t%d %s', c.length, self.basename)
self._bytesEmitted += c.length
// no point saving empty chunks
if (!c.length) {
return
} else if (self._paused || self._buffer.length) {
self._buffer.push(c)
self._read()
} else self.emit('data', c)
})
stream.on('end', function () {
if (self._paused || self._buffer.length) {
// console.error('FR Buffering End', self._path)
self._buffer.push(EOF)
self._read()
} else {
self.emit('end')
}
if (self._bytesEmitted !== self.props.size) {
self.error("Didn't get expected byte count\n" +
'expect: ' + self.props.size + '\n' +
'actual: ' + self._bytesEmitted)
}
})
stream.on('close', function () {
if (self._paused || self._buffer.length) {
// console.error('FR Buffering Close', self._path)
self._buffer.push(CLOSE)
self._read()
} else {
// console.error('FR close 1', self._path)
self.emit('close')
}
})
stream.on('error', function (e) {
self.emit('error', e)
})
self._read()
}
FileReader.prototype._read = function () {
var self = this
// console.error('FR _read', self._path)
if (self._paused) {
// console.error('FR _read paused', self._path)
return
}
if (!self._stream) {
// console.error('FR _getStream calling', self._path)
return self._getStream()
}
// clear out the buffer, if there is one.
if (self._buffer.length) {
// console.error('FR _read has buffer', self._buffer.length, self._path)
var buf = self._buffer
for (var i = 0, l = buf.length; i < l; i++) {
var c = buf[i]
if (c === EOF) {
// console.error('FR Read emitting buffered end', self._path)
self.emit('end')
} else if (c === CLOSE) {
// console.error('FR Read emitting buffered close', self._path)
self.emit('close')
} else {
// console.error('FR Read emitting buffered data', self._path)
self.emit('data', c)
}
if (self._paused) {
// console.error('FR Read Re-pausing at '+i, self._path)
self._buffer = buf.slice(i)
return
}
}
self._buffer.length = 0
}
// console.error("FR _read done")
// that's about all there is to it.
}
FileReader.prototype.pause = function (who) {
var self = this
// console.error('FR Pause', self._path)
if (self._paused) return
who = who || self
self._paused = true
if (self._stream) self._stream.pause()
self.emit('pause', who)
}
FileReader.prototype.resume = function (who) {
var self = this
// console.error('FR Resume', self._path)
if (!self._paused) return
who = who || self
self.emit('resume', who)
self._paused = false
if (self._stream) self._stream.resume()
self._read()
}
@@ -1,107 +0,0 @@
module.exports = FileWriter
var fs = require('graceful-fs')
var Writer = require('./writer.js')
var inherits = require('inherits')
var EOF = {}
inherits(FileWriter, Writer)
function FileWriter (props) {
var self = this
if (!(self instanceof FileWriter)) {
throw new Error('FileWriter must be called as constructor.')
}
// should already be established as a File type
if (props.type !== 'File' || !props.File) {
throw new Error('Non-file type ' + props.type)
}
self._buffer = []
self._bytesWritten = 0
Writer.call(this, props)
}
FileWriter.prototype._create = function () {
var self = this
if (self._stream) return
var so = {}
if (self.props.flags) so.flags = self.props.flags
so.mode = Writer.filemode
if (self._old && self._old.blksize) so.bufferSize = self._old.blksize
self._stream = fs.createWriteStream(self._path, so)
self._stream.on('open', function () {
// console.error("FW open", self._buffer, self._path)
self.ready = true
self._buffer.forEach(function (c) {
if (c === EOF) self._stream.end()
else self._stream.write(c)
})
self.emit('ready')
// give this a kick just in case it needs it.
self.emit('drain')
})
self._stream.on('error', function (er) { self.emit('error', er) })
self._stream.on('drain', function () { self.emit('drain') })
self._stream.on('close', function () {
// console.error('\n\nFW Stream Close', self._path, self.size)
self._finish()
})
}
FileWriter.prototype.write = function (c) {
var self = this
self._bytesWritten += c.length
if (!self.ready) {
if (!Buffer.isBuffer(c) && typeof c !== 'string') {
throw new Error('invalid write data')
}
self._buffer.push(c)
return false
}
var ret = self._stream.write(c)
// console.error('\t-- fw wrote, _stream says', ret, self._stream._queue.length)
// allow 2 buffered writes, because otherwise there's just too
// much stop and go bs.
if (ret === false && self._stream._queue) {
return self._stream._queue.length <= 2
} else {
return ret
}
}
FileWriter.prototype.end = function (c) {
var self = this
if (c) self.write(c)
if (!self.ready) {
self._buffer.push(EOF)
return false
}
return self._stream.end()
}
FileWriter.prototype._finish = function () {
var self = this
if (typeof self.size === 'number' && self._bytesWritten !== self.size) {
self.error(
'Did not get expected byte count.\n' +
'expect: ' + self.size + '\n' +
'actual: ' + self._bytesWritten)
}
Writer.prototype._finish.call(self)
}
-33
View File
@@ -1,33 +0,0 @@
module.exports = getType
function getType (st) {
var types = [
'Directory',
'File',
'SymbolicLink',
'Link', // special for hardlinks from tarballs
'BlockDevice',
'CharacterDevice',
'FIFO',
'Socket'
]
var type
if (st.type && types.indexOf(st.type) !== -1) {
st[st.type] = true
return st.type
}
for (var i = 0, l = types.length; i < l; i++) {
type = types[i]
var is = st[type] || st['is' + type]
if (typeof is === 'function') is = is.call(st)
if (is) {
st[type] = true
st.type = type
return type
}
}
return null
}
@@ -1,53 +0,0 @@
// Basically just a wrapper around an fs.readlink
//
// XXX: Enhance this to support the Link type, by keeping
// a lookup table of {<dev+inode>:<path>}, so that hardlinks
// can be preserved in tarballs.
module.exports = LinkReader
var fs = require('graceful-fs')
var inherits = require('inherits')
var Reader = require('./reader.js')
inherits(LinkReader, Reader)
function LinkReader (props) {
var self = this
if (!(self instanceof LinkReader)) {
throw new Error('LinkReader must be called as constructor.')
}
if (!((props.type === 'Link' && props.Link) ||
(props.type === 'SymbolicLink' && props.SymbolicLink))) {
throw new Error('Non-link type ' + props.type)
}
Reader.call(self, props)
}
// When piping a LinkReader into a LinkWriter, we have to
// already have the linkpath property set, so that has to
// happen *before* the "ready" event, which means we need to
// override the _stat method.
LinkReader.prototype._stat = function (currentStat) {
var self = this
fs.readlink(self._path, function (er, linkpath) {
if (er) return self.error(er)
self.linkpath = self.props.linkpath = linkpath
self.emit('linkpath', linkpath)
Reader.prototype._stat.call(self, currentStat)
})
}
LinkReader.prototype._read = function () {
var self = this
if (self._paused) return
// basically just a no-op, since we got all the info we need
// from the _stat method
if (!self._ended) {
self.emit('end')
self.emit('close')
self._ended = true
}
}
@@ -1,95 +0,0 @@
module.exports = LinkWriter
var fs = require('graceful-fs')
var Writer = require('./writer.js')
var inherits = require('inherits')
var path = require('path')
var rimraf = require('rimraf')
inherits(LinkWriter, Writer)
function LinkWriter (props) {
var self = this
if (!(self instanceof LinkWriter)) {
throw new Error('LinkWriter must be called as constructor.')
}
// should already be established as a Link type
if (!((props.type === 'Link' && props.Link) ||
(props.type === 'SymbolicLink' && props.SymbolicLink))) {
throw new Error('Non-link type ' + props.type)
}
if (props.linkpath === '') props.linkpath = '.'
if (!props.linkpath) {
self.error('Need linkpath property to create ' + props.type)
}
Writer.call(this, props)
}
LinkWriter.prototype._create = function () {
// console.error(" LW _create")
var self = this
var hard = self.type === 'Link' || process.platform === 'win32'
var link = hard ? 'link' : 'symlink'
var lp = hard ? path.resolve(self.dirname, self.linkpath) : self.linkpath
// can only change the link path by clobbering
// For hard links, let's just assume that's always the case, since
// there's no good way to read them if we don't already know.
if (hard) return clobber(self, lp, link)
fs.readlink(self._path, function (er, p) {
// only skip creation if it's exactly the same link
if (p && p === lp) return finish(self)
clobber(self, lp, link)
})
}
function clobber (self, lp, link) {
rimraf(self._path, function (er) {
if (er) return self.error(er)
create(self, lp, link)
})
}
function create (self, lp, link) {
fs[link](lp, self._path, function (er) {
// if this is a hard link, and we're in the process of writing out a
// directory, it's very possible that the thing we're linking to
// doesn't exist yet (especially if it was intended as a symlink),
// so swallow ENOENT errors here and just soldier in.
// Additionally, an EPERM or EACCES can happen on win32 if it's trying
// to make a link to a directory. Again, just skip it.
// A better solution would be to have fs.symlink be supported on
// windows in some nice fashion.
if (er) {
if ((er.code === 'ENOENT' ||
er.code === 'EACCES' ||
er.code === 'EPERM') && process.platform === 'win32') {
self.ready = true
self.emit('ready')
self.emit('end')
self.emit('close')
self.end = self._finish = function () {}
} else return self.error(er)
}
finish(self)
})
}
function finish (self) {
self.ready = true
self.emit('ready')
if (self._ended && !self._finished) self._finish()
}
LinkWriter.prototype.end = function () {
// console.error("LW finish in end")
this._ended = true
if (this.ready) {
this._finished = true
this._finish()
}
}
@@ -1,95 +0,0 @@
// A reader for when we don't yet know what kind of thing
// the thing is.
module.exports = ProxyReader
var Reader = require('./reader.js')
var getType = require('./get-type.js')
var inherits = require('inherits')
var fs = require('graceful-fs')
inherits(ProxyReader, Reader)
function ProxyReader (props) {
var self = this
if (!(self instanceof ProxyReader)) {
throw new Error('ProxyReader must be called as constructor.')
}
self.props = props
self._buffer = []
self.ready = false
Reader.call(self, props)
}
ProxyReader.prototype._stat = function () {
var self = this
var props = self.props
// stat the thing to see what the proxy should be.
var stat = props.follow ? 'stat' : 'lstat'
fs[stat](props.path, function (er, current) {
var type
if (er || !current) {
type = 'File'
} else {
type = getType(current)
}
props[type] = true
props.type = self.type = type
self._old = current
self._addProxy(Reader(props, current))
})
}
ProxyReader.prototype._addProxy = function (proxy) {
var self = this
if (self._proxyTarget) {
return self.error('proxy already set')
}
self._proxyTarget = proxy
proxy._proxy = self
;[
'error',
'data',
'end',
'close',
'linkpath',
'entry',
'entryEnd',
'child',
'childEnd',
'warn',
'stat'
].forEach(function (ev) {
// console.error('~~ proxy event', ev, self.path)
proxy.on(ev, self.emit.bind(self, ev))
})
self.emit('proxy', proxy)
proxy.on('ready', function () {
// console.error("~~ proxy is ready!", self.path)
self.ready = true
self.emit('ready')
})
var calls = self._buffer
self._buffer.length = 0
calls.forEach(function (c) {
proxy[c[0]].apply(proxy, c[1])
})
}
ProxyReader.prototype.pause = function () {
return this._proxyTarget ? this._proxyTarget.pause() : false
}
ProxyReader.prototype.resume = function () {
return this._proxyTarget ? this._proxyTarget.resume() : false
}
@@ -1,111 +0,0 @@
// A writer for when we don't know what kind of thing
// the thing is. That is, it's not explicitly set,
// so we're going to make it whatever the thing already
// is, or "File"
//
// Until then, collect all events.
module.exports = ProxyWriter
var Writer = require('./writer.js')
var getType = require('./get-type.js')
var inherits = require('inherits')
var collect = require('./collect.js')
var fs = require('fs')
inherits(ProxyWriter, Writer)
function ProxyWriter (props) {
var self = this
if (!(self instanceof ProxyWriter)) {
throw new Error('ProxyWriter must be called as constructor.')
}
self.props = props
self._needDrain = false
Writer.call(self, props)
}
ProxyWriter.prototype._stat = function () {
var self = this
var props = self.props
// stat the thing to see what the proxy should be.
var stat = props.follow ? 'stat' : 'lstat'
fs[stat](props.path, function (er, current) {
var type
if (er || !current) {
type = 'File'
} else {
type = getType(current)
}
props[type] = true
props.type = self.type = type
self._old = current
self._addProxy(Writer(props, current))
})
}
ProxyWriter.prototype._addProxy = function (proxy) {
// console.error("~~ set proxy", this.path)
var self = this
if (self._proxy) {
return self.error('proxy already set')
}
self._proxy = proxy
;[
'ready',
'error',
'close',
'pipe',
'drain',
'warn'
].forEach(function (ev) {
proxy.on(ev, self.emit.bind(self, ev))
})
self.emit('proxy', proxy)
var calls = self._buffer
calls.forEach(function (c) {
// console.error("~~ ~~ proxy buffered call", c[0], c[1])
proxy[c[0]].apply(proxy, c[1])
})
self._buffer.length = 0
if (self._needsDrain) self.emit('drain')
}
ProxyWriter.prototype.add = function (entry) {
// console.error("~~ proxy add")
collect(entry)
if (!this._proxy) {
this._buffer.push(['add', [entry]])
this._needDrain = true
return false
}
return this._proxy.add(entry)
}
ProxyWriter.prototype.write = function (c) {
// console.error('~~ proxy write')
if (!this._proxy) {
this._buffer.push(['write', [c]])
this._needDrain = true
return false
}
return this._proxy.write(c)
}
ProxyWriter.prototype.end = function (c) {
// console.error('~~ proxy end')
if (!this._proxy) {
this._buffer.push(['end', [c]])
return false
}
return this._proxy.end(c)
}
-255
View File
@@ -1,255 +0,0 @@
module.exports = Reader
var fs = require('graceful-fs')
var Stream = require('stream').Stream
var inherits = require('inherits')
var path = require('path')
var getType = require('./get-type.js')
var hardLinks = Reader.hardLinks = {}
var Abstract = require('./abstract.js')
// Must do this *before* loading the child classes
inherits(Reader, Abstract)
var LinkReader = require('./link-reader.js')
function Reader (props, currentStat) {
var self = this
if (!(self instanceof Reader)) return new Reader(props, currentStat)
if (typeof props === 'string') {
props = { path: props }
}
// polymorphism.
// call fstream.Reader(dir) to get a DirReader object, etc.
// Note that, unlike in the Writer case, ProxyReader is going
// to be the *normal* state of affairs, since we rarely know
// the type of a file prior to reading it.
var type
var ClassType
if (props.type && typeof props.type === 'function') {
type = props.type
ClassType = type
} else {
type = getType(props)
ClassType = Reader
}
if (currentStat && !type) {
type = getType(currentStat)
props[type] = true
props.type = type
}
switch (type) {
case 'Directory':
ClassType = require('./dir-reader.js')
break
case 'Link':
// XXX hard links are just files.
// However, it would be good to keep track of files' dev+inode
// and nlink values, and create a HardLinkReader that emits
// a linkpath value of the original copy, so that the tar
// writer can preserve them.
// ClassType = HardLinkReader
// break
case 'File':
ClassType = require('./file-reader.js')
break
case 'SymbolicLink':
ClassType = LinkReader
break
case 'Socket':
ClassType = require('./socket-reader.js')
break
case null:
ClassType = require('./proxy-reader.js')
break
}
if (!(self instanceof ClassType)) {
return new ClassType(props)
}
Abstract.call(self)
if (!props.path) {
self.error('Must provide a path', null, true)
}
self.readable = true
self.writable = false
self.type = type
self.props = props
self.depth = props.depth = props.depth || 0
self.parent = props.parent || null
self.root = props.root || (props.parent && props.parent.root) || self
self._path = self.path = path.resolve(props.path)
if (process.platform === 'win32') {
self.path = self._path = self.path.replace(/\?/g, '_')
if (self._path.length >= 260) {
// how DOES one create files on the moon?
// if the path has spaces in it, then UNC will fail.
self._swallowErrors = true
// if (self._path.indexOf(" ") === -1) {
self._path = '\\\\?\\' + self.path.replace(/\//g, '\\')
// }
}
}
self.basename = props.basename = path.basename(self.path)
self.dirname = props.dirname = path.dirname(self.path)
// these have served their purpose, and are now just noisy clutter
props.parent = props.root = null
// console.error("\n\n\n%s setting size to", props.path, props.size)
self.size = props.size
self.filter = typeof props.filter === 'function' ? props.filter : null
if (props.sort === 'alpha') props.sort = alphasort
// start the ball rolling.
// this will stat the thing, and then call self._read()
// to start reading whatever it is.
// console.error("calling stat", props.path, currentStat)
self._stat(currentStat)
}
function alphasort (a, b) {
return a === b ? 0
: a.toLowerCase() > b.toLowerCase() ? 1
: a.toLowerCase() < b.toLowerCase() ? -1
: a > b ? 1
: -1
}
Reader.prototype._stat = function (currentStat) {
var self = this
var props = self.props
var stat = props.follow ? 'stat' : 'lstat'
// console.error("Reader._stat", self._path, currentStat)
if (currentStat) process.nextTick(statCb.bind(null, null, currentStat))
else fs[stat](self._path, statCb)
function statCb (er, props_) {
// console.error("Reader._stat, statCb", self._path, props_, props_.nlink)
if (er) return self.error(er)
Object.keys(props_).forEach(function (k) {
props[k] = props_[k]
})
// if it's not the expected size, then abort here.
if (undefined !== self.size && props.size !== self.size) {
return self.error('incorrect size')
}
self.size = props.size
var type = getType(props)
var handleHardlinks = props.hardlinks !== false
// special little thing for handling hardlinks.
if (handleHardlinks && type !== 'Directory' && props.nlink && props.nlink > 1) {
var k = props.dev + ':' + props.ino
// console.error("Reader has nlink", self._path, k)
if (hardLinks[k] === self._path || !hardLinks[k]) {
hardLinks[k] = self._path
} else {
// switch into hardlink mode.
type = self.type = self.props.type = 'Link'
self.Link = self.props.Link = true
self.linkpath = self.props.linkpath = hardLinks[k]
// console.error("Hardlink detected, switching mode", self._path, self.linkpath)
// Setting __proto__ would arguably be the "correct"
// approach here, but that just seems too wrong.
self._stat = self._read = LinkReader.prototype._read
}
}
if (self.type && self.type !== type) {
self.error('Unexpected type: ' + type)
}
// if the filter doesn't pass, then just skip over this one.
// still have to emit end so that dir-walking can move on.
if (self.filter) {
var who = self._proxy || self
// special handling for ProxyReaders
if (!self.filter.call(who, who, props)) {
if (!self._disowned) {
self.abort()
self.emit('end')
self.emit('close')
}
return
}
}
// last chance to abort or disown before the flow starts!
var events = ['_stat', 'stat', 'ready']
var e = 0
;(function go () {
if (self._aborted) {
self.emit('end')
self.emit('close')
return
}
if (self._paused && self.type !== 'Directory') {
self.once('resume', go)
return
}
var ev = events[e++]
if (!ev) {
return self._read()
}
self.emit(ev, props)
go()
})()
}
}
Reader.prototype.pipe = function (dest) {
var self = this
if (typeof dest.add === 'function') {
// piping to a multi-compatible, and we've got directory entries.
self.on('entry', function (entry) {
var ret = dest.add(entry)
if (ret === false) {
self.pause()
}
})
}
// console.error("R Pipe apply Stream Pipe")
return Stream.prototype.pipe.apply(this, arguments)
}
Reader.prototype.pause = function (who) {
this._paused = true
who = who || this
this.emit('pause', who)
if (this._stream) this._stream.pause(who)
}
Reader.prototype.resume = function (who) {
this._paused = false
who = who || this
this.emit('resume', who)
if (this._stream) this._stream.resume(who)
this._read()
}
Reader.prototype._read = function () {
this.error('Cannot read unknown type: ' + this.type)
}
@@ -1,36 +0,0 @@
// Just get the stats, and then don't do anything.
// You can't really "read" from a socket. You "connect" to it.
// Mostly, this is here so that reading a dir with a socket in it
// doesn't blow up.
module.exports = SocketReader
var inherits = require('inherits')
var Reader = require('./reader.js')
inherits(SocketReader, Reader)
function SocketReader (props) {
var self = this
if (!(self instanceof SocketReader)) {
throw new Error('SocketReader must be called as constructor.')
}
if (!(props.type === 'Socket' && props.Socket)) {
throw new Error('Non-socket type ' + props.type)
}
Reader.call(self, props)
}
SocketReader.prototype._read = function () {
var self = this
if (self._paused) return
// basically just a no-op, since we got all the info we have
// from the _stat method
if (!self._ended) {
self.emit('end')
self.emit('close')
self._ended = true
}
}
-390
View File
@@ -1,390 +0,0 @@
module.exports = Writer
var fs = require('graceful-fs')
var inherits = require('inherits')
var rimraf = require('rimraf')
var mkdir = require('mkdirp')
var path = require('path')
var umask = process.platform === 'win32' ? 0 : process.umask()
var getType = require('./get-type.js')
var Abstract = require('./abstract.js')
// Must do this *before* loading the child classes
inherits(Writer, Abstract)
Writer.dirmode = parseInt('0777', 8) & (~umask)
Writer.filemode = parseInt('0666', 8) & (~umask)
var DirWriter = require('./dir-writer.js')
var LinkWriter = require('./link-writer.js')
var FileWriter = require('./file-writer.js')
var ProxyWriter = require('./proxy-writer.js')
// props is the desired state. current is optionally the current stat,
// provided here so that subclasses can avoid statting the target
// more than necessary.
function Writer (props, current) {
var self = this
if (typeof props === 'string') {
props = { path: props }
}
// polymorphism.
// call fstream.Writer(dir) to get a DirWriter object, etc.
var type = getType(props)
var ClassType = Writer
switch (type) {
case 'Directory':
ClassType = DirWriter
break
case 'File':
ClassType = FileWriter
break
case 'Link':
case 'SymbolicLink':
ClassType = LinkWriter
break
case null:
default:
// Don't know yet what type to create, so we wrap in a proxy.
ClassType = ProxyWriter
break
}
if (!(self instanceof ClassType)) return new ClassType(props)
// now get down to business.
Abstract.call(self)
if (!props.path) self.error('Must provide a path', null, true)
// props is what we want to set.
// set some convenience properties as well.
self.type = props.type
self.props = props
self.depth = props.depth || 0
self.clobber = props.clobber === false ? props.clobber : true
self.parent = props.parent || null
self.root = props.root || (props.parent && props.parent.root) || self
self._path = self.path = path.resolve(props.path)
if (process.platform === 'win32') {
self.path = self._path = self.path.replace(/\?/g, '_')
if (self._path.length >= 260) {
self._swallowErrors = true
self._path = '\\\\?\\' + self.path.replace(/\//g, '\\')
}
}
self.basename = path.basename(props.path)
self.dirname = path.dirname(props.path)
self.linkpath = props.linkpath || null
props.parent = props.root = null
// console.error("\n\n\n%s setting size to", props.path, props.size)
self.size = props.size
if (typeof props.mode === 'string') {
props.mode = parseInt(props.mode, 8)
}
self.readable = false
self.writable = true
// buffer until ready, or while handling another entry
self._buffer = []
self.ready = false
self.filter = typeof props.filter === 'function' ? props.filter : null
// start the ball rolling.
// this checks what's there already, and then calls
// self._create() to call the impl-specific creation stuff.
self._stat(current)
}
// Calling this means that it's something we can't create.
// Just assert that it's already there, otherwise raise a warning.
Writer.prototype._create = function () {
var self = this
fs[self.props.follow ? 'stat' : 'lstat'](self._path, function (er) {
if (er) {
return self.warn('Cannot create ' + self._path + '\n' +
'Unsupported type: ' + self.type, 'ENOTSUP')
}
self._finish()
})
}
Writer.prototype._stat = function (current) {
var self = this
var props = self.props
var stat = props.follow ? 'stat' : 'lstat'
var who = self._proxy || self
if (current) statCb(null, current)
else fs[stat](self._path, statCb)
function statCb (er, current) {
if (self.filter && !self.filter.call(who, who, current)) {
self._aborted = true
self.emit('end')
self.emit('close')
return
}
// if it's not there, great. We'll just create it.
// if it is there, then we'll need to change whatever differs
if (er || !current) {
return create(self)
}
self._old = current
var currentType = getType(current)
// if it's a type change, then we need to clobber or error.
// if it's not a type change, then let the impl take care of it.
if (currentType !== self.type || self.type === 'File' && current.nlink > 1) {
return rimraf(self._path, function (er) {
if (er) return self.error(er)
self._old = null
create(self)
})
}
// otherwise, just handle in the app-specific way
// this creates a fs.WriteStream, or mkdir's, or whatever
create(self)
}
}
function create (self) {
// console.error("W create", self._path, Writer.dirmode)
// XXX Need to clobber non-dirs that are in the way,
// unless { clobber: false } in the props.
mkdir(path.dirname(self._path), Writer.dirmode, function (er, made) {
// console.error("W created", path.dirname(self._path), er)
if (er) return self.error(er)
// later on, we have to set the mode and owner for these
self._madeDir = made
return self._create()
})
}
function endChmod (self, want, current, path, cb) {
var wantMode = want.mode
var chmod = want.follow || self.type !== 'SymbolicLink'
? 'chmod' : 'lchmod'
if (!fs[chmod]) return cb()
if (typeof wantMode !== 'number') return cb()
var curMode = current.mode & parseInt('0777', 8)
wantMode = wantMode & parseInt('0777', 8)
if (wantMode === curMode) return cb()
fs[chmod](path, wantMode, cb)
}
function endChown (self, want, current, path, cb) {
// Don't even try it unless root. Too easy to EPERM.
if (process.platform === 'win32') return cb()
if (!process.getuid || process.getuid() !== 0) return cb()
if (typeof want.uid !== 'number' &&
typeof want.gid !== 'number') return cb()
if (current.uid === want.uid &&
current.gid === want.gid) return cb()
var chown = (self.props.follow || self.type !== 'SymbolicLink')
? 'chown' : 'lchown'
if (!fs[chown]) return cb()
if (typeof want.uid !== 'number') want.uid = current.uid
if (typeof want.gid !== 'number') want.gid = current.gid
fs[chown](path, want.uid, want.gid, cb)
}
function endUtimes (self, want, current, path, cb) {
if (!fs.utimes || process.platform === 'win32') return cb()
var utimes = (want.follow || self.type !== 'SymbolicLink')
? 'utimes' : 'lutimes'
if (utimes === 'lutimes' && !fs[utimes]) {
utimes = 'utimes'
}
if (!fs[utimes]) return cb()
var curA = current.atime
var curM = current.mtime
var meA = want.atime
var meM = want.mtime
if (meA === undefined) meA = curA
if (meM === undefined) meM = curM
if (!isDate(meA)) meA = new Date(meA)
if (!isDate(meM)) meA = new Date(meM)
if (meA.getTime() === curA.getTime() &&
meM.getTime() === curM.getTime()) return cb()
fs[utimes](path, meA, meM, cb)
}
// XXX This function is beastly. Break it up!
Writer.prototype._finish = function () {
var self = this
if (self._finishing) return
self._finishing = true
// console.error(" W Finish", self._path, self.size)
// set up all the things.
// At this point, we're already done writing whatever we've gotta write,
// adding files to the dir, etc.
var todo = 0
var errState = null
var done = false
if (self._old) {
// the times will almost *certainly* have changed.
// adds the utimes syscall, but remove another stat.
self._old.atime = new Date(0)
self._old.mtime = new Date(0)
// console.error(" W Finish Stale Stat", self._path, self.size)
setProps(self._old)
} else {
var stat = self.props.follow ? 'stat' : 'lstat'
// console.error(" W Finish Stating", self._path, self.size)
fs[stat](self._path, function (er, current) {
// console.error(" W Finish Stated", self._path, self.size, current)
if (er) {
// if we're in the process of writing out a
// directory, it's very possible that the thing we're linking to
// doesn't exist yet (especially if it was intended as a symlink),
// so swallow ENOENT errors here and just soldier on.
if (er.code === 'ENOENT' &&
(self.type === 'Link' || self.type === 'SymbolicLink') &&
process.platform === 'win32') {
self.ready = true
self.emit('ready')
self.emit('end')
self.emit('close')
self.end = self._finish = function () {}
return
} else return self.error(er)
}
setProps(self._old = current)
})
}
return
function setProps (current) {
todo += 3
endChmod(self, self.props, current, self._path, next('chmod'))
endChown(self, self.props, current, self._path, next('chown'))
endUtimes(self, self.props, current, self._path, next('utimes'))
}
function next (what) {
return function (er) {
// console.error(" W Finish", what, todo)
if (errState) return
if (er) {
er.fstream_finish_call = what
return self.error(errState = er)
}
if (--todo > 0) return
if (done) return
done = true
// we may still need to set the mode/etc. on some parent dirs
// that were created previously. delay end/close until then.
if (!self._madeDir) return end()
else endMadeDir(self, self._path, end)
function end (er) {
if (er) {
er.fstream_finish_call = 'setupMadeDir'
return self.error(er)
}
// all the props have been set, so we're completely done.
self.emit('end')
self.emit('close')
}
}
}
}
function endMadeDir (self, p, cb) {
var made = self._madeDir
// everything *between* made and path.dirname(self._path)
// needs to be set up. Note that this may just be one dir.
var d = path.dirname(p)
endMadeDir_(self, d, function (er) {
if (er) return cb(er)
if (d === made) {
return cb()
}
endMadeDir(self, d, cb)
})
}
function endMadeDir_ (self, p, cb) {
var dirProps = {}
Object.keys(self.props).forEach(function (k) {
dirProps[k] = self.props[k]
// only make non-readable dirs if explicitly requested.
if (k === 'mode' && self.type !== 'Directory') {
dirProps[k] = dirProps[k] | parseInt('0111', 8)
}
})
var todo = 3
var errState = null
fs.stat(p, function (er, current) {
if (er) return cb(errState = er)
endChmod(self, dirProps, current, p, next)
endChown(self, dirProps, current, p, next)
endUtimes(self, dirProps, current, p, next)
})
function next (er) {
if (errState) return
if (er) return cb(errState = er)
if (--todo === 0) return cb()
}
}
Writer.prototype.pipe = function () {
this.error("Can't pipe from writable stream")
}
Writer.prototype.add = function () {
this.error("Can't add to non-Directory type")
}
Writer.prototype.write = function () {
return true
}
function objectToString (d) {
return Object.prototype.toString.call(d)
}
function isDate (d) {
return typeof d === 'object' && objectToString(d) === '[object Date]'
}
-28
View File
@@ -1,28 +0,0 @@
{
"author": "Isaac Z. Schlueter <i@izs.me> (http://blog.izs.me/)",
"name": "fstream",
"description": "Advanced file system stream things",
"version": "1.0.12",
"repository": {
"type": "git",
"url": "https://github.com/npm/fstream.git"
},
"main": "fstream.js",
"engines": {
"node": ">=0.6"
},
"dependencies": {
"graceful-fs": "^4.1.2",
"inherits": "~2.0.0",
"mkdirp": ">=0.5 0",
"rimraf": "2"
},
"devDependencies": {
"standard": "^4.0.0",
"tap": "^1.2.0"
},
"scripts": {
"test": "standard && tap examples/*.js"
},
"license": "ISC"
}
-21
View File
@@ -1,21 +0,0 @@
The ISC License
Copyright (c) Isaac Z. Schlueter and Contributors
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
## Glob Logo
Glob's logo created by Tanya Brassie <http://tanyabrassie.com/>, licensed
under a Creative Commons Attribution-ShareAlike 4.0 International License
https://creativecommons.org/licenses/by-sa/4.0/
-378
View File
@@ -1,378 +0,0 @@
# Glob
Match files using the patterns the shell uses, like stars and stuff.
[![Build Status](https://travis-ci.org/isaacs/node-glob.svg?branch=master)](https://travis-ci.org/isaacs/node-glob/) [![Build Status](https://ci.appveyor.com/api/projects/status/kd7f3yftf7unxlsx?svg=true)](https://ci.appveyor.com/project/isaacs/node-glob) [![Coverage Status](https://coveralls.io/repos/isaacs/node-glob/badge.svg?branch=master&service=github)](https://coveralls.io/github/isaacs/node-glob?branch=master)
This is a glob implementation in JavaScript. It uses the `minimatch`
library to do its matching.
![a fun cartoon logo made of glob characters](logo/glob.png)
## Usage
Install with npm
```
npm i glob
```
```javascript
var glob = require("glob")
// options is optional
glob("**/*.js", options, function (er, files) {
// files is an array of filenames.
// If the `nonull` option is set, and nothing
// was found, then files is ["**/*.js"]
// er is an error object or null.
})
```
## Glob Primer
"Globs" are the patterns you type when you do stuff like `ls *.js` on
the command line, or put `build/*` in a `.gitignore` file.
Before parsing the path part patterns, braced sections are expanded
into a set. Braced sections start with `{` and end with `}`, with any
number of comma-delimited sections within. Braced sections may contain
slash characters, so `a{/b/c,bcd}` would expand into `a/b/c` and `abcd`.
The following characters have special magic meaning when used in a
path portion:
* `*` Matches 0 or more characters in a single path portion
* `?` Matches 1 character
* `[...]` Matches a range of characters, similar to a RegExp range.
If the first character of the range is `!` or `^` then it matches
any character not in the range.
* `!(pattern|pattern|pattern)` Matches anything that does not match
any of the patterns provided.
* `?(pattern|pattern|pattern)` Matches zero or one occurrence of the
patterns provided.
* `+(pattern|pattern|pattern)` Matches one or more occurrences of the
patterns provided.
* `*(a|b|c)` Matches zero or more occurrences of the patterns provided
* `@(pattern|pat*|pat?erN)` Matches exactly one of the patterns
provided
* `**` If a "globstar" is alone in a path portion, then it matches
zero or more directories and subdirectories searching for matches.
It does not crawl symlinked directories.
### Dots
If a file or directory path portion has a `.` as the first character,
then it will not match any glob pattern unless that pattern's
corresponding path part also has a `.` as its first character.
For example, the pattern `a/.*/c` would match the file at `a/.b/c`.
However the pattern `a/*/c` would not, because `*` does not start with
a dot character.
You can make glob treat dots as normal characters by setting
`dot:true` in the options.
### Basename Matching
If you set `matchBase:true` in the options, and the pattern has no
slashes in it, then it will seek for any file anywhere in the tree
with a matching basename. For example, `*.js` would match
`test/simple/basic.js`.
### Empty Sets
If no matching files are found, then an empty array is returned. This
differs from the shell, where the pattern itself is returned. For
example:
$ echo a*s*d*f
a*s*d*f
To get the bash-style behavior, set the `nonull:true` in the options.
### See Also:
* `man sh`
* `man bash` (Search for "Pattern Matching")
* `man 3 fnmatch`
* `man 5 gitignore`
* [minimatch documentation](https://github.com/isaacs/minimatch)
## glob.hasMagic(pattern, [options])
Returns `true` if there are any special characters in the pattern, and
`false` otherwise.
Note that the options affect the results. If `noext:true` is set in
the options object, then `+(a|b)` will not be considered a magic
pattern. If the pattern has a brace expansion, like `a/{b/c,x/y}`
then that is considered magical, unless `nobrace:true` is set in the
options.
## glob(pattern, [options], cb)
* `pattern` `{String}` Pattern to be matched
* `options` `{Object}`
* `cb` `{Function}`
* `err` `{Error | null}`
* `matches` `{Array<String>}` filenames found matching the pattern
Perform an asynchronous glob search.
## glob.sync(pattern, [options])
* `pattern` `{String}` Pattern to be matched
* `options` `{Object}`
* return: `{Array<String>}` filenames found matching the pattern
Perform a synchronous glob search.
## Class: glob.Glob
Create a Glob object by instantiating the `glob.Glob` class.
```javascript
var Glob = require("glob").Glob
var mg = new Glob(pattern, options, cb)
```
It's an EventEmitter, and starts walking the filesystem to find matches
immediately.
### new glob.Glob(pattern, [options], [cb])
* `pattern` `{String}` pattern to search for
* `options` `{Object}`
* `cb` `{Function}` Called when an error occurs, or matches are found
* `err` `{Error | null}`
* `matches` `{Array<String>}` filenames found matching the pattern
Note that if the `sync` flag is set in the options, then matches will
be immediately available on the `g.found` member.
### Properties
* `minimatch` The minimatch object that the glob uses.
* `options` The options object passed in.
* `aborted` Boolean which is set to true when calling `abort()`. There
is no way at this time to continue a glob search after aborting, but
you can re-use the statCache to avoid having to duplicate syscalls.
* `cache` Convenience object. Each field has the following possible
values:
* `false` - Path does not exist
* `true` - Path exists
* `'FILE'` - Path exists, and is not a directory
* `'DIR'` - Path exists, and is a directory
* `[file, entries, ...]` - Path exists, is a directory, and the
array value is the results of `fs.readdir`
* `statCache` Cache of `fs.stat` results, to prevent statting the same
path multiple times.
* `symlinks` A record of which paths are symbolic links, which is
relevant in resolving `**` patterns.
* `realpathCache` An optional object which is passed to `fs.realpath`
to minimize unnecessary syscalls. It is stored on the instantiated
Glob object, and may be re-used.
### Events
* `end` When the matching is finished, this is emitted with all the
matches found. If the `nonull` option is set, and no match was found,
then the `matches` list contains the original pattern. The matches
are sorted, unless the `nosort` flag is set.
* `match` Every time a match is found, this is emitted with the specific
thing that matched. It is not deduplicated or resolved to a realpath.
* `error` Emitted when an unexpected error is encountered, or whenever
any fs error occurs if `options.strict` is set.
* `abort` When `abort()` is called, this event is raised.
### Methods
* `pause` Temporarily stop the search
* `resume` Resume the search
* `abort` Stop the search forever
### Options
All the options that can be passed to Minimatch can also be passed to
Glob to change pattern matching behavior. Also, some have been added,
or have glob-specific ramifications.
All options are false by default, unless otherwise noted.
All options are added to the Glob object, as well.
If you are running many `glob` operations, you can pass a Glob object
as the `options` argument to a subsequent operation to shortcut some
`stat` and `readdir` calls. At the very least, you may pass in shared
`symlinks`, `statCache`, `realpathCache`, and `cache` options, so that
parallel glob operations will be sped up by sharing information about
the filesystem.
* `cwd` The current working directory in which to search. Defaults
to `process.cwd()`.
* `root` The place where patterns starting with `/` will be mounted
onto. Defaults to `path.resolve(options.cwd, "/")` (`/` on Unix
systems, and `C:\` or some such on Windows.)
* `dot` Include `.dot` files in normal matches and `globstar` matches.
Note that an explicit dot in a portion of the pattern will always
match dot files.
* `nomount` By default, a pattern starting with a forward-slash will be
"mounted" onto the root setting, so that a valid filesystem path is
returned. Set this flag to disable that behavior.
* `mark` Add a `/` character to directory matches. Note that this
requires additional stat calls.
* `nosort` Don't sort the results.
* `stat` Set to true to stat *all* results. This reduces performance
somewhat, and is completely unnecessary, unless `readdir` is presumed
to be an untrustworthy indicator of file existence.
* `silent` When an unusual error is encountered when attempting to
read a directory, a warning will be printed to stderr. Set the
`silent` option to true to suppress these warnings.
* `strict` When an unusual error is encountered when attempting to
read a directory, the process will just continue on in search of
other matches. Set the `strict` option to raise an error in these
cases.
* `cache` See `cache` property above. Pass in a previously generated
cache object to save some fs calls.
* `statCache` A cache of results of filesystem information, to prevent
unnecessary stat calls. While it should not normally be necessary
to set this, you may pass the statCache from one glob() call to the
options object of another, if you know that the filesystem will not
change between calls. (See "Race Conditions" below.)
* `symlinks` A cache of known symbolic links. You may pass in a
previously generated `symlinks` object to save `lstat` calls when
resolving `**` matches.
* `sync` DEPRECATED: use `glob.sync(pattern, opts)` instead.
* `nounique` In some cases, brace-expanded patterns can result in the
same file showing up multiple times in the result set. By default,
this implementation prevents duplicates in the result set. Set this
flag to disable that behavior.
* `nonull` Set to never return an empty set, instead returning a set
containing the pattern itself. This is the default in glob(3).
* `debug` Set to enable debug logging in minimatch and glob.
* `nobrace` Do not expand `{a,b}` and `{1..3}` brace sets.
* `noglobstar` Do not match `**` against multiple filenames. (Ie,
treat it as a normal `*` instead.)
* `noext` Do not match `+(a|b)` "extglob" patterns.
* `nocase` Perform a case-insensitive match. Note: on
case-insensitive filesystems, non-magic patterns will match by
default, since `stat` and `readdir` will not raise errors.
* `matchBase` Perform a basename-only match if the pattern does not
contain any slash characters. That is, `*.js` would be treated as
equivalent to `**/*.js`, matching all js files in all directories.
* `nodir` Do not match directories, only files. (Note: to match
*only* directories, simply put a `/` at the end of the pattern.)
* `ignore` Add a pattern or an array of glob patterns to exclude matches.
Note: `ignore` patterns are *always* in `dot:true` mode, regardless
of any other settings.
* `follow` Follow symlinked directories when expanding `**` patterns.
Note that this can result in a lot of duplicate references in the
presence of cyclic links.
* `realpath` Set to true to call `fs.realpath` on all of the results.
In the case of a symlink that cannot be resolved, the full absolute
path to the matched entry is returned (though it will usually be a
broken symlink)
* `absolute` Set to true to always receive absolute paths for matched
files. Unlike `realpath`, this also affects the values returned in
the `match` event.
* `fs` File-system object with Node's `fs` API. By default, the built-in
`fs` module will be used. Set to a volume provided by a library like
`memfs` to avoid using the "real" file-system.
## Comparisons to other fnmatch/glob implementations
While strict compliance with the existing standards is a worthwhile
goal, some discrepancies exist between node-glob and other
implementations, and are intentional.
The double-star character `**` is supported by default, unless the
`noglobstar` flag is set. This is supported in the manner of bsdglob
and bash 4.3, where `**` only has special significance if it is the only
thing in a path part. That is, `a/**/b` will match `a/x/y/b`, but
`a/**b` will not.
Note that symlinked directories are not crawled as part of a `**`,
though their contents may match against subsequent portions of the
pattern. This prevents infinite loops and duplicates and the like.
If an escaped pattern has no matches, and the `nonull` flag is set,
then glob returns the pattern as-provided, rather than
interpreting the character escapes. For example,
`glob.match([], "\\*a\\?")` will return `"\\*a\\?"` rather than
`"*a?"`. This is akin to setting the `nullglob` option in bash, except
that it does not resolve escaped pattern characters.
If brace expansion is not disabled, then it is performed before any
other interpretation of the glob pattern. Thus, a pattern like
`+(a|{b),c)}`, which would not be valid in bash or zsh, is expanded
**first** into the set of `+(a|b)` and `+(a|c)`, and those patterns are
checked for validity. Since those two are valid, matching proceeds.
### Comments and Negation
Previously, this module let you mark a pattern as a "comment" if it
started with a `#` character, or a "negated" pattern if it started
with a `!` character.
These options were deprecated in version 5, and removed in version 6.
To specify things that should not match, use the `ignore` option.
## Windows
**Please only use forward-slashes in glob expressions.**
Though windows uses either `/` or `\` as its path separator, only `/`
characters are used by this glob implementation. You must use
forward-slashes **only** in glob expressions. Back-slashes will always
be interpreted as escape characters, not path separators.
Results from absolute patterns such as `/foo/*` are mounted onto the
root setting using `path.join`. On windows, this will by default result
in `/foo/*` matching `C:\foo\bar.txt`.
## Race Conditions
Glob searching, by its very nature, is susceptible to race conditions,
since it relies on directory walking and such.
As a result, it is possible that a file that exists when glob looks for
it may have been deleted or modified by the time it returns the result.
As part of its internal implementation, this program caches all stat
and readdir calls that it makes, in order to cut down on system
overhead. However, this also makes it even more susceptible to races,
especially if the cache or statCache objects are reused between glob
calls.
Users are thus advised not to use a glob result as a guarantee of
filesystem state in the face of rapid changes. For the vast majority
of operations, this is never a problem.
## Glob Logo
Glob's logo was created by [Tanya Brassie](http://tanyabrassie.com/). Logo files can be found [here](https://github.com/isaacs/node-glob/tree/master/logo).
The logo is licensed under a [Creative Commons Attribution-ShareAlike 4.0 International License](https://creativecommons.org/licenses/by-sa/4.0/).
## Contributing
Any change to behavior (including bugfixes) must come with a test.
Patches that fail tests or reduce performance will be rejected.
```
# to run tests
npm test
# to re-generate test fixtures
npm run test-regen
# to benchmark against bash/zsh
npm run bench
# to profile javascript
npm run prof
```
![](oh-my-glob.gif)
-236
View File
@@ -1,236 +0,0 @@
exports.setopts = setopts
exports.ownProp = ownProp
exports.makeAbs = makeAbs
exports.finish = finish
exports.mark = mark
exports.isIgnored = isIgnored
exports.childrenIgnored = childrenIgnored
function ownProp (obj, field) {
return Object.prototype.hasOwnProperty.call(obj, field)
}
var fs = require("fs")
var path = require("path")
var minimatch = require("minimatch")
var isAbsolute = require("path-is-absolute")
var Minimatch = minimatch.Minimatch
function alphasort (a, b) {
return a.localeCompare(b, 'en')
}
function setupIgnores (self, options) {
self.ignore = options.ignore || []
if (!Array.isArray(self.ignore))
self.ignore = [self.ignore]
if (self.ignore.length) {
self.ignore = self.ignore.map(ignoreMap)
}
}
// ignore patterns are always in dot:true mode.
function ignoreMap (pattern) {
var gmatcher = null
if (pattern.slice(-3) === '/**') {
var gpattern = pattern.replace(/(\/\*\*)+$/, '')
gmatcher = new Minimatch(gpattern, { dot: true })
}
return {
matcher: new Minimatch(pattern, { dot: true }),
gmatcher: gmatcher
}
}
function setopts (self, pattern, options) {
if (!options)
options = {}
// base-matching: just use globstar for that.
if (options.matchBase && -1 === pattern.indexOf("/")) {
if (options.noglobstar) {
throw new Error("base matching requires globstar")
}
pattern = "**/" + pattern
}
self.silent = !!options.silent
self.pattern = pattern
self.strict = options.strict !== false
self.realpath = !!options.realpath
self.realpathCache = options.realpathCache || Object.create(null)
self.follow = !!options.follow
self.dot = !!options.dot
self.mark = !!options.mark
self.nodir = !!options.nodir
if (self.nodir)
self.mark = true
self.sync = !!options.sync
self.nounique = !!options.nounique
self.nonull = !!options.nonull
self.nosort = !!options.nosort
self.nocase = !!options.nocase
self.stat = !!options.stat
self.noprocess = !!options.noprocess
self.absolute = !!options.absolute
self.fs = options.fs || fs
self.maxLength = options.maxLength || Infinity
self.cache = options.cache || Object.create(null)
self.statCache = options.statCache || Object.create(null)
self.symlinks = options.symlinks || Object.create(null)
setupIgnores(self, options)
self.changedCwd = false
var cwd = process.cwd()
if (!ownProp(options, "cwd"))
self.cwd = cwd
else {
self.cwd = path.resolve(options.cwd)
self.changedCwd = self.cwd !== cwd
}
self.root = options.root || path.resolve(self.cwd, "/")
self.root = path.resolve(self.root)
if (process.platform === "win32")
self.root = self.root.replace(/\\/g, "/")
// TODO: is an absolute `cwd` supposed to be resolved against `root`?
// e.g. { cwd: '/test', root: __dirname } === path.join(__dirname, '/test')
self.cwdAbs = isAbsolute(self.cwd) ? self.cwd : makeAbs(self, self.cwd)
if (process.platform === "win32")
self.cwdAbs = self.cwdAbs.replace(/\\/g, "/")
self.nomount = !!options.nomount
// disable comments and negation in Minimatch.
// Note that they are not supported in Glob itself anyway.
options.nonegate = true
options.nocomment = true
self.minimatch = new Minimatch(pattern, options)
self.options = self.minimatch.options
}
function finish (self) {
var nou = self.nounique
var all = nou ? [] : Object.create(null)
for (var i = 0, l = self.matches.length; i < l; i ++) {
var matches = self.matches[i]
if (!matches || Object.keys(matches).length === 0) {
if (self.nonull) {
// do like the shell, and spit out the literal glob
var literal = self.minimatch.globSet[i]
if (nou)
all.push(literal)
else
all[literal] = true
}
} else {
// had matches
var m = Object.keys(matches)
if (nou)
all.push.apply(all, m)
else
m.forEach(function (m) {
all[m] = true
})
}
}
if (!nou)
all = Object.keys(all)
if (!self.nosort)
all = all.sort(alphasort)
// at *some* point we statted all of these
if (self.mark) {
for (var i = 0; i < all.length; i++) {
all[i] = self._mark(all[i])
}
if (self.nodir) {
all = all.filter(function (e) {
var notDir = !(/\/$/.test(e))
var c = self.cache[e] || self.cache[makeAbs(self, e)]
if (notDir && c)
notDir = c !== 'DIR' && !Array.isArray(c)
return notDir
})
}
}
if (self.ignore.length)
all = all.filter(function(m) {
return !isIgnored(self, m)
})
self.found = all
}
function mark (self, p) {
var abs = makeAbs(self, p)
var c = self.cache[abs]
var m = p
if (c) {
var isDir = c === 'DIR' || Array.isArray(c)
var slash = p.slice(-1) === '/'
if (isDir && !slash)
m += '/'
else if (!isDir && slash)
m = m.slice(0, -1)
if (m !== p) {
var mabs = makeAbs(self, m)
self.statCache[mabs] = self.statCache[abs]
self.cache[mabs] = self.cache[abs]
}
}
return m
}
// lotta situps...
function makeAbs (self, f) {
var abs = f
if (f.charAt(0) === '/') {
abs = path.join(self.root, f)
} else if (isAbsolute(f) || f === '') {
abs = f
} else if (self.changedCwd) {
abs = path.resolve(self.cwd, f)
} else {
abs = path.resolve(f)
}
if (process.platform === 'win32')
abs = abs.replace(/\\/g, '/')
return abs
}
// Return true, if pattern ends with globstar '**', for the accompanying parent directory.
// Ex:- If node_modules/** is the pattern, add 'node_modules' to ignore list along with it's contents
function isIgnored (self, path) {
if (!self.ignore.length)
return false
return self.ignore.some(function(item) {
return item.matcher.match(path) || !!(item.gmatcher && item.gmatcher.match(path))
})
}
function childrenIgnored (self, path) {
if (!self.ignore.length)
return false
return self.ignore.some(function(item) {
return !!(item.gmatcher && item.gmatcher.match(path))
})
}
-787
View File
@@ -1,787 +0,0 @@
// Approach:
//
// 1. Get the minimatch set
// 2. For each pattern in the set, PROCESS(pattern, false)
// 3. Store matches per-set, then uniq them
//
// PROCESS(pattern, inGlobStar)
// Get the first [n] items from pattern that are all strings
// Join these together. This is PREFIX.
// If there is no more remaining, then stat(PREFIX) and
// add to matches if it succeeds. END.
//
// If inGlobStar and PREFIX is symlink and points to dir
// set ENTRIES = []
// else readdir(PREFIX) as ENTRIES
// If fail, END
//
// with ENTRIES
// If pattern[n] is GLOBSTAR
// // handle the case where the globstar match is empty
// // by pruning it out, and testing the resulting pattern
// PROCESS(pattern[0..n] + pattern[n+1 .. $], false)
// // handle other cases.
// for ENTRY in ENTRIES (not dotfiles)
// // attach globstar + tail onto the entry
// // Mark that this entry is a globstar match
// PROCESS(pattern[0..n] + ENTRY + pattern[n .. $], true)
//
// else // not globstar
// for ENTRY in ENTRIES (not dotfiles, unless pattern[n] is dot)
// Test ENTRY against pattern[n]
// If fails, continue
// If passes, PROCESS(pattern[0..n] + item + pattern[n+1 .. $])
//
// Caveat:
// Cache all stats and readdirs results to minimize syscall. Since all
// we ever care about is existence and directory-ness, we can just keep
// `true` for files, and [children,...] for directories, or `false` for
// things that don't exist.
module.exports = glob
var rp = require('fs.realpath')
var minimatch = require('minimatch')
var Minimatch = minimatch.Minimatch
var inherits = require('inherits')
var EE = require('events').EventEmitter
var path = require('path')
var assert = require('assert')
var isAbsolute = require('path-is-absolute')
var globSync = require('./sync.js')
var common = require('./common.js')
var setopts = common.setopts
var ownProp = common.ownProp
var inflight = require('inflight')
var util = require('util')
var childrenIgnored = common.childrenIgnored
var isIgnored = common.isIgnored
var once = require('once')
function glob (pattern, options, cb) {
if (typeof options === 'function') cb = options, options = {}
if (!options) options = {}
if (options.sync) {
if (cb)
throw new TypeError('callback provided to sync glob')
return globSync(pattern, options)
}
return new Glob(pattern, options, cb)
}
glob.sync = globSync
var GlobSync = glob.GlobSync = globSync.GlobSync
// old api surface
glob.glob = glob
function extend (origin, add) {
if (add === null || typeof add !== 'object') {
return origin
}
var keys = Object.keys(add)
var i = keys.length
while (i--) {
origin[keys[i]] = add[keys[i]]
}
return origin
}
glob.hasMagic = function (pattern, options_) {
var options = extend({}, options_)
options.noprocess = true
var g = new Glob(pattern, options)
var set = g.minimatch.set
if (!pattern)
return false
if (set.length > 1)
return true
for (var j = 0; j < set[0].length; j++) {
if (typeof set[0][j] !== 'string')
return true
}
return false
}
glob.Glob = Glob
inherits(Glob, EE)
function Glob (pattern, options, cb) {
if (typeof options === 'function') {
cb = options
options = null
}
if (options && options.sync) {
if (cb)
throw new TypeError('callback provided to sync glob')
return new GlobSync(pattern, options)
}
if (!(this instanceof Glob))
return new Glob(pattern, options, cb)
setopts(this, pattern, options)
this._didRealPath = false
// process each pattern in the minimatch set
var n = this.minimatch.set.length
// The matches are stored as {<filename>: true,...} so that
// duplicates are automagically pruned.
// Later, we do an Object.keys() on these.
// Keep them as a list so we can fill in when nonull is set.
this.matches = new Array(n)
if (typeof cb === 'function') {
cb = once(cb)
this.on('error', cb)
this.on('end', function (matches) {
cb(null, matches)
})
}
var self = this
this._processing = 0
this._emitQueue = []
this._processQueue = []
this.paused = false
if (this.noprocess)
return this
if (n === 0)
return done()
var sync = true
for (var i = 0; i < n; i ++) {
this._process(this.minimatch.set[i], i, false, done)
}
sync = false
function done () {
--self._processing
if (self._processing <= 0) {
if (sync) {
process.nextTick(function () {
self._finish()
})
} else {
self._finish()
}
}
}
}
Glob.prototype._finish = function () {
assert(this instanceof Glob)
if (this.aborted)
return
if (this.realpath && !this._didRealpath)
return this._realpath()
common.finish(this)
this.emit('end', this.found)
}
Glob.prototype._realpath = function () {
if (this._didRealpath)
return
this._didRealpath = true
var n = this.matches.length
if (n === 0)
return this._finish()
var self = this
for (var i = 0; i < this.matches.length; i++)
this._realpathSet(i, next)
function next () {
if (--n === 0)
self._finish()
}
}
Glob.prototype._realpathSet = function (index, cb) {
var matchset = this.matches[index]
if (!matchset)
return cb()
var found = Object.keys(matchset)
var self = this
var n = found.length
if (n === 0)
return cb()
var set = this.matches[index] = Object.create(null)
found.forEach(function (p, i) {
// If there's a problem with the stat, then it means that
// one or more of the links in the realpath couldn't be
// resolved. just return the abs value in that case.
p = self._makeAbs(p)
rp.realpath(p, self.realpathCache, function (er, real) {
if (!er)
set[real] = true
else if (er.syscall === 'stat')
set[p] = true
else
self.emit('error', er) // srsly wtf right here
if (--n === 0) {
self.matches[index] = set
cb()
}
})
})
}
Glob.prototype._mark = function (p) {
return common.mark(this, p)
}
Glob.prototype._makeAbs = function (f) {
return common.makeAbs(this, f)
}
Glob.prototype.abort = function () {
this.aborted = true
this.emit('abort')
}
Glob.prototype.pause = function () {
if (!this.paused) {
this.paused = true
this.emit('pause')
}
}
Glob.prototype.resume = function () {
if (this.paused) {
this.emit('resume')
this.paused = false
if (this._emitQueue.length) {
var eq = this._emitQueue.slice(0)
this._emitQueue.length = 0
for (var i = 0; i < eq.length; i ++) {
var e = eq[i]
this._emitMatch(e[0], e[1])
}
}
if (this._processQueue.length) {
var pq = this._processQueue.slice(0)
this._processQueue.length = 0
for (var i = 0; i < pq.length; i ++) {
var p = pq[i]
this._processing--
this._process(p[0], p[1], p[2], p[3])
}
}
}
}
Glob.prototype._process = function (pattern, index, inGlobStar, cb) {
assert(this instanceof Glob)
assert(typeof cb === 'function')
if (this.aborted)
return
this._processing++
if (this.paused) {
this._processQueue.push([pattern, index, inGlobStar, cb])
return
}
//console.error('PROCESS %d', this._processing, pattern)
// Get the first [n] parts of pattern that are all strings.
var n = 0
while (typeof pattern[n] === 'string') {
n ++
}
// now n is the index of the first one that is *not* a string.
// see if there's anything else
var prefix
switch (n) {
// if not, then this is rather simple
case pattern.length:
this._processSimple(pattern.join('/'), index, cb)
return
case 0:
// pattern *starts* with some non-trivial item.
// going to readdir(cwd), but not include the prefix in matches.
prefix = null
break
default:
// pattern has some string bits in the front.
// whatever it starts with, whether that's 'absolute' like /foo/bar,
// or 'relative' like '../baz'
prefix = pattern.slice(0, n).join('/')
break
}
var remain = pattern.slice(n)
// get the list of entries.
var read
if (prefix === null)
read = '.'
else if (isAbsolute(prefix) || isAbsolute(pattern.join('/'))) {
if (!prefix || !isAbsolute(prefix))
prefix = '/' + prefix
read = prefix
} else
read = prefix
var abs = this._makeAbs(read)
//if ignored, skip _processing
if (childrenIgnored(this, read))
return cb()
var isGlobStar = remain[0] === minimatch.GLOBSTAR
if (isGlobStar)
this._processGlobStar(prefix, read, abs, remain, index, inGlobStar, cb)
else
this._processReaddir(prefix, read, abs, remain, index, inGlobStar, cb)
}
Glob.prototype._processReaddir = function (prefix, read, abs, remain, index, inGlobStar, cb) {
var self = this
this._readdir(abs, inGlobStar, function (er, entries) {
return self._processReaddir2(prefix, read, abs, remain, index, inGlobStar, entries, cb)
})
}
Glob.prototype._processReaddir2 = function (prefix, read, abs, remain, index, inGlobStar, entries, cb) {
// if the abs isn't a dir, then nothing can match!
if (!entries)
return cb()
// It will only match dot entries if it starts with a dot, or if
// dot is set. Stuff like @(.foo|.bar) isn't allowed.
var pn = remain[0]
var negate = !!this.minimatch.negate
var rawGlob = pn._glob
var dotOk = this.dot || rawGlob.charAt(0) === '.'
var matchedEntries = []
for (var i = 0; i < entries.length; i++) {
var e = entries[i]
if (e.charAt(0) !== '.' || dotOk) {
var m
if (negate && !prefix) {
m = !e.match(pn)
} else {
m = e.match(pn)
}
if (m)
matchedEntries.push(e)
}
}
//console.error('prd2', prefix, entries, remain[0]._glob, matchedEntries)
var len = matchedEntries.length
// If there are no matched entries, then nothing matches.
if (len === 0)
return cb()
// if this is the last remaining pattern bit, then no need for
// an additional stat *unless* the user has specified mark or
// stat explicitly. We know they exist, since readdir returned
// them.
if (remain.length === 1 && !this.mark && !this.stat) {
if (!this.matches[index])
this.matches[index] = Object.create(null)
for (var i = 0; i < len; i ++) {
var e = matchedEntries[i]
if (prefix) {
if (prefix !== '/')
e = prefix + '/' + e
else
e = prefix + e
}
if (e.charAt(0) === '/' && !this.nomount) {
e = path.join(this.root, e)
}
this._emitMatch(index, e)
}
// This was the last one, and no stats were needed
return cb()
}
// now test all matched entries as stand-ins for that part
// of the pattern.
remain.shift()
for (var i = 0; i < len; i ++) {
var e = matchedEntries[i]
var newPattern
if (prefix) {
if (prefix !== '/')
e = prefix + '/' + e
else
e = prefix + e
}
this._process([e].concat(remain), index, inGlobStar, cb)
}
cb()
}
Glob.prototype._emitMatch = function (index, e) {
if (this.aborted)
return
if (isIgnored(this, e))
return
if (this.paused) {
this._emitQueue.push([index, e])
return
}
var abs = isAbsolute(e) ? e : this._makeAbs(e)
if (this.mark)
e = this._mark(e)
if (this.absolute)
e = abs
if (this.matches[index][e])
return
if (this.nodir) {
var c = this.cache[abs]
if (c === 'DIR' || Array.isArray(c))
return
}
this.matches[index][e] = true
var st = this.statCache[abs]
if (st)
this.emit('stat', e, st)
this.emit('match', e)
}
Glob.prototype._readdirInGlobStar = function (abs, cb) {
if (this.aborted)
return
// follow all symlinked directories forever
// just proceed as if this is a non-globstar situation
if (this.follow)
return this._readdir(abs, false, cb)
var lstatkey = 'lstat\0' + abs
var self = this
var lstatcb = inflight(lstatkey, lstatcb_)
if (lstatcb)
self.fs.lstat(abs, lstatcb)
function lstatcb_ (er, lstat) {
if (er && er.code === 'ENOENT')
return cb()
var isSym = lstat && lstat.isSymbolicLink()
self.symlinks[abs] = isSym
// If it's not a symlink or a dir, then it's definitely a regular file.
// don't bother doing a readdir in that case.
if (!isSym && lstat && !lstat.isDirectory()) {
self.cache[abs] = 'FILE'
cb()
} else
self._readdir(abs, false, cb)
}
}
Glob.prototype._readdir = function (abs, inGlobStar, cb) {
if (this.aborted)
return
cb = inflight('readdir\0'+abs+'\0'+inGlobStar, cb)
if (!cb)
return
//console.error('RD %j %j', +inGlobStar, abs)
if (inGlobStar && !ownProp(this.symlinks, abs))
return this._readdirInGlobStar(abs, cb)
if (ownProp(this.cache, abs)) {
var c = this.cache[abs]
if (!c || c === 'FILE')
return cb()
if (Array.isArray(c))
return cb(null, c)
}
var self = this
self.fs.readdir(abs, readdirCb(this, abs, cb))
}
function readdirCb (self, abs, cb) {
return function (er, entries) {
if (er)
self._readdirError(abs, er, cb)
else
self._readdirEntries(abs, entries, cb)
}
}
Glob.prototype._readdirEntries = function (abs, entries, cb) {
if (this.aborted)
return
// if we haven't asked to stat everything, then just
// assume that everything in there exists, so we can avoid
// having to stat it a second time.
if (!this.mark && !this.stat) {
for (var i = 0; i < entries.length; i ++) {
var e = entries[i]
if (abs === '/')
e = abs + e
else
e = abs + '/' + e
this.cache[e] = true
}
}
this.cache[abs] = entries
return cb(null, entries)
}
Glob.prototype._readdirError = function (f, er, cb) {
if (this.aborted)
return
// handle errors, and cache the information
switch (er.code) {
case 'ENOTSUP': // https://github.com/isaacs/node-glob/issues/205
case 'ENOTDIR': // totally normal. means it *does* exist.
var abs = this._makeAbs(f)
this.cache[abs] = 'FILE'
if (abs === this.cwdAbs) {
var error = new Error(er.code + ' invalid cwd ' + this.cwd)
error.path = this.cwd
error.code = er.code
this.emit('error', error)
this.abort()
}
break
case 'ENOENT': // not terribly unusual
case 'ELOOP':
case 'ENAMETOOLONG':
case 'UNKNOWN':
this.cache[this._makeAbs(f)] = false
break
default: // some unusual error. Treat as failure.
this.cache[this._makeAbs(f)] = false
if (this.strict) {
this.emit('error', er)
// If the error is handled, then we abort
// if not, we threw out of here
this.abort()
}
if (!this.silent)
console.error('glob error', er)
break
}
return cb()
}
Glob.prototype._processGlobStar = function (prefix, read, abs, remain, index, inGlobStar, cb) {
var self = this
this._readdir(abs, inGlobStar, function (er, entries) {
self._processGlobStar2(prefix, read, abs, remain, index, inGlobStar, entries, cb)
})
}
Glob.prototype._processGlobStar2 = function (prefix, read, abs, remain, index, inGlobStar, entries, cb) {
//console.error('pgs2', prefix, remain[0], entries)
// no entries means not a dir, so it can never have matches
// foo.txt/** doesn't match foo.txt
if (!entries)
return cb()
// test without the globstar, and with every child both below
// and replacing the globstar.
var remainWithoutGlobStar = remain.slice(1)
var gspref = prefix ? [ prefix ] : []
var noGlobStar = gspref.concat(remainWithoutGlobStar)
// the noGlobStar pattern exits the inGlobStar state
this._process(noGlobStar, index, false, cb)
var isSym = this.symlinks[abs]
var len = entries.length
// If it's a symlink, and we're in a globstar, then stop
if (isSym && inGlobStar)
return cb()
for (var i = 0; i < len; i++) {
var e = entries[i]
if (e.charAt(0) === '.' && !this.dot)
continue
// these two cases enter the inGlobStar state
var instead = gspref.concat(entries[i], remainWithoutGlobStar)
this._process(instead, index, true, cb)
var below = gspref.concat(entries[i], remain)
this._process(below, index, true, cb)
}
cb()
}
Glob.prototype._processSimple = function (prefix, index, cb) {
// XXX review this. Shouldn't it be doing the mounting etc
// before doing stat? kinda weird?
var self = this
this._stat(prefix, function (er, exists) {
self._processSimple2(prefix, index, er, exists, cb)
})
}
Glob.prototype._processSimple2 = function (prefix, index, er, exists, cb) {
//console.error('ps2', prefix, exists)
if (!this.matches[index])
this.matches[index] = Object.create(null)
// If it doesn't exist, then just mark the lack of results
if (!exists)
return cb()
if (prefix && isAbsolute(prefix) && !this.nomount) {
var trail = /[\/\\]$/.test(prefix)
if (prefix.charAt(0) === '/') {
prefix = path.join(this.root, prefix)
} else {
prefix = path.resolve(this.root, prefix)
if (trail)
prefix += '/'
}
}
if (process.platform === 'win32')
prefix = prefix.replace(/\\/g, '/')
// Mark this as a match
this._emitMatch(index, prefix)
cb()
}
// Returns either 'DIR', 'FILE', or false
Glob.prototype._stat = function (f, cb) {
var abs = this._makeAbs(f)
var needDir = f.slice(-1) === '/'
if (f.length > this.maxLength)
return cb()
if (!this.stat && ownProp(this.cache, abs)) {
var c = this.cache[abs]
if (Array.isArray(c))
c = 'DIR'
// It exists, but maybe not how we need it
if (!needDir || c === 'DIR')
return cb(null, c)
if (needDir && c === 'FILE')
return cb()
// otherwise we have to stat, because maybe c=true
// if we know it exists, but not what it is.
}
var exists
var stat = this.statCache[abs]
if (stat !== undefined) {
if (stat === false)
return cb(null, stat)
else {
var type = stat.isDirectory() ? 'DIR' : 'FILE'
if (needDir && type === 'FILE')
return cb()
else
return cb(null, type, stat)
}
}
var self = this
var statcb = inflight('stat\0' + abs, lstatcb_)
if (statcb)
self.fs.lstat(abs, statcb)
function lstatcb_ (er, lstat) {
if (lstat && lstat.isSymbolicLink()) {
// If it's a symlink, then treat it as the target, unless
// the target does not exist, then treat it as a file.
return self.fs.stat(abs, function (er, stat) {
if (er)
self._stat2(f, abs, null, lstat, cb)
else
self._stat2(f, abs, er, stat, cb)
})
} else {
self._stat2(f, abs, er, lstat, cb)
}
}
}
Glob.prototype._stat2 = function (f, abs, er, stat, cb) {
if (er && (er.code === 'ENOENT' || er.code === 'ENOTDIR')) {
this.statCache[abs] = false
return cb()
}
var needDir = f.slice(-1) === '/'
this.statCache[abs] = stat
if (abs.slice(-1) === '/' && stat && !stat.isDirectory())
return cb(null, false, stat)
var c = true
if (stat)
c = stat.isDirectory() ? 'DIR' : 'FILE'
this.cache[abs] = this.cache[abs] || c
if (needDir && c === 'FILE')
return cb()
return cb(null, c, stat)
}
-52
View File
@@ -1,52 +0,0 @@
{
"author": "Isaac Z. Schlueter <i@izs.me> (http://blog.izs.me/)",
"name": "glob",
"description": "a little globber",
"version": "7.2.0",
"repository": {
"type": "git",
"url": "git://github.com/isaacs/node-glob.git"
},
"main": "glob.js",
"files": [
"glob.js",
"sync.js",
"common.js"
],
"engines": {
"node": "*"
},
"dependencies": {
"fs.realpath": "^1.0.0",
"inflight": "^1.0.4",
"inherits": "2",
"minimatch": "^3.0.4",
"once": "^1.3.0",
"path-is-absolute": "^1.0.0"
},
"devDependencies": {
"memfs": "^3.2.0",
"mkdirp": "0",
"rimraf": "^2.2.8",
"tap": "^15.0.6",
"tick": "0.0.6"
},
"tap": {
"before": "test/00-setup.js",
"after": "test/zz-cleanup.js",
"jobs": 1
},
"scripts": {
"prepublish": "npm run benchclean",
"profclean": "rm -f v8.log profile.txt",
"test": "tap",
"test-regen": "npm run profclean && TEST_REGEN=1 node test/00-setup.js",
"bench": "bash benchmark.sh",
"prof": "bash prof.sh && cat profile.txt",
"benchclean": "node benchclean.js"
},
"license": "ISC",
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
}
-483
View File
@@ -1,483 +0,0 @@
module.exports = globSync
globSync.GlobSync = GlobSync
var rp = require('fs.realpath')
var minimatch = require('minimatch')
var Minimatch = minimatch.Minimatch
var Glob = require('./glob.js').Glob
var util = require('util')
var path = require('path')
var assert = require('assert')
var isAbsolute = require('path-is-absolute')
var common = require('./common.js')
var setopts = common.setopts
var ownProp = common.ownProp
var childrenIgnored = common.childrenIgnored
var isIgnored = common.isIgnored
function globSync (pattern, options) {
if (typeof options === 'function' || arguments.length === 3)
throw new TypeError('callback provided to sync glob\n'+
'See: https://github.com/isaacs/node-glob/issues/167')
return new GlobSync(pattern, options).found
}
function GlobSync (pattern, options) {
if (!pattern)
throw new Error('must provide pattern')
if (typeof options === 'function' || arguments.length === 3)
throw new TypeError('callback provided to sync glob\n'+
'See: https://github.com/isaacs/node-glob/issues/167')
if (!(this instanceof GlobSync))
return new GlobSync(pattern, options)
setopts(this, pattern, options)
if (this.noprocess)
return this
var n = this.minimatch.set.length
this.matches = new Array(n)
for (var i = 0; i < n; i ++) {
this._process(this.minimatch.set[i], i, false)
}
this._finish()
}
GlobSync.prototype._finish = function () {
assert(this instanceof GlobSync)
if (this.realpath) {
var self = this
this.matches.forEach(function (matchset, index) {
var set = self.matches[index] = Object.create(null)
for (var p in matchset) {
try {
p = self._makeAbs(p)
var real = rp.realpathSync(p, self.realpathCache)
set[real] = true
} catch (er) {
if (er.syscall === 'stat')
set[self._makeAbs(p)] = true
else
throw er
}
}
})
}
common.finish(this)
}
GlobSync.prototype._process = function (pattern, index, inGlobStar) {
assert(this instanceof GlobSync)
// Get the first [n] parts of pattern that are all strings.
var n = 0
while (typeof pattern[n] === 'string') {
n ++
}
// now n is the index of the first one that is *not* a string.
// See if there's anything else
var prefix
switch (n) {
// if not, then this is rather simple
case pattern.length:
this._processSimple(pattern.join('/'), index)
return
case 0:
// pattern *starts* with some non-trivial item.
// going to readdir(cwd), but not include the prefix in matches.
prefix = null
break
default:
// pattern has some string bits in the front.
// whatever it starts with, whether that's 'absolute' like /foo/bar,
// or 'relative' like '../baz'
prefix = pattern.slice(0, n).join('/')
break
}
var remain = pattern.slice(n)
// get the list of entries.
var read
if (prefix === null)
read = '.'
else if (isAbsolute(prefix) || isAbsolute(pattern.join('/'))) {
if (!prefix || !isAbsolute(prefix))
prefix = '/' + prefix
read = prefix
} else
read = prefix
var abs = this._makeAbs(read)
//if ignored, skip processing
if (childrenIgnored(this, read))
return
var isGlobStar = remain[0] === minimatch.GLOBSTAR
if (isGlobStar)
this._processGlobStar(prefix, read, abs, remain, index, inGlobStar)
else
this._processReaddir(prefix, read, abs, remain, index, inGlobStar)
}
GlobSync.prototype._processReaddir = function (prefix, read, abs, remain, index, inGlobStar) {
var entries = this._readdir(abs, inGlobStar)
// if the abs isn't a dir, then nothing can match!
if (!entries)
return
// It will only match dot entries if it starts with a dot, or if
// dot is set. Stuff like @(.foo|.bar) isn't allowed.
var pn = remain[0]
var negate = !!this.minimatch.negate
var rawGlob = pn._glob
var dotOk = this.dot || rawGlob.charAt(0) === '.'
var matchedEntries = []
for (var i = 0; i < entries.length; i++) {
var e = entries[i]
if (e.charAt(0) !== '.' || dotOk) {
var m
if (negate && !prefix) {
m = !e.match(pn)
} else {
m = e.match(pn)
}
if (m)
matchedEntries.push(e)
}
}
var len = matchedEntries.length
// If there are no matched entries, then nothing matches.
if (len === 0)
return
// if this is the last remaining pattern bit, then no need for
// an additional stat *unless* the user has specified mark or
// stat explicitly. We know they exist, since readdir returned
// them.
if (remain.length === 1 && !this.mark && !this.stat) {
if (!this.matches[index])
this.matches[index] = Object.create(null)
for (var i = 0; i < len; i ++) {
var e = matchedEntries[i]
if (prefix) {
if (prefix.slice(-1) !== '/')
e = prefix + '/' + e
else
e = prefix + e
}
if (e.charAt(0) === '/' && !this.nomount) {
e = path.join(this.root, e)
}
this._emitMatch(index, e)
}
// This was the last one, and no stats were needed
return
}
// now test all matched entries as stand-ins for that part
// of the pattern.
remain.shift()
for (var i = 0; i < len; i ++) {
var e = matchedEntries[i]
var newPattern
if (prefix)
newPattern = [prefix, e]
else
newPattern = [e]
this._process(newPattern.concat(remain), index, inGlobStar)
}
}
GlobSync.prototype._emitMatch = function (index, e) {
if (isIgnored(this, e))
return
var abs = this._makeAbs(e)
if (this.mark)
e = this._mark(e)
if (this.absolute) {
e = abs
}
if (this.matches[index][e])
return
if (this.nodir) {
var c = this.cache[abs]
if (c === 'DIR' || Array.isArray(c))
return
}
this.matches[index][e] = true
if (this.stat)
this._stat(e)
}
GlobSync.prototype._readdirInGlobStar = function (abs) {
// follow all symlinked directories forever
// just proceed as if this is a non-globstar situation
if (this.follow)
return this._readdir(abs, false)
var entries
var lstat
var stat
try {
lstat = this.fs.lstatSync(abs)
} catch (er) {
if (er.code === 'ENOENT') {
// lstat failed, doesn't exist
return null
}
}
var isSym = lstat && lstat.isSymbolicLink()
this.symlinks[abs] = isSym
// If it's not a symlink or a dir, then it's definitely a regular file.
// don't bother doing a readdir in that case.
if (!isSym && lstat && !lstat.isDirectory())
this.cache[abs] = 'FILE'
else
entries = this._readdir(abs, false)
return entries
}
GlobSync.prototype._readdir = function (abs, inGlobStar) {
var entries
if (inGlobStar && !ownProp(this.symlinks, abs))
return this._readdirInGlobStar(abs)
if (ownProp(this.cache, abs)) {
var c = this.cache[abs]
if (!c || c === 'FILE')
return null
if (Array.isArray(c))
return c
}
try {
return this._readdirEntries(abs, this.fs.readdirSync(abs))
} catch (er) {
this._readdirError(abs, er)
return null
}
}
GlobSync.prototype._readdirEntries = function (abs, entries) {
// if we haven't asked to stat everything, then just
// assume that everything in there exists, so we can avoid
// having to stat it a second time.
if (!this.mark && !this.stat) {
for (var i = 0; i < entries.length; i ++) {
var e = entries[i]
if (abs === '/')
e = abs + e
else
e = abs + '/' + e
this.cache[e] = true
}
}
this.cache[abs] = entries
// mark and cache dir-ness
return entries
}
GlobSync.prototype._readdirError = function (f, er) {
// handle errors, and cache the information
switch (er.code) {
case 'ENOTSUP': // https://github.com/isaacs/node-glob/issues/205
case 'ENOTDIR': // totally normal. means it *does* exist.
var abs = this._makeAbs(f)
this.cache[abs] = 'FILE'
if (abs === this.cwdAbs) {
var error = new Error(er.code + ' invalid cwd ' + this.cwd)
error.path = this.cwd
error.code = er.code
throw error
}
break
case 'ENOENT': // not terribly unusual
case 'ELOOP':
case 'ENAMETOOLONG':
case 'UNKNOWN':
this.cache[this._makeAbs(f)] = false
break
default: // some unusual error. Treat as failure.
this.cache[this._makeAbs(f)] = false
if (this.strict)
throw er
if (!this.silent)
console.error('glob error', er)
break
}
}
GlobSync.prototype._processGlobStar = function (prefix, read, abs, remain, index, inGlobStar) {
var entries = this._readdir(abs, inGlobStar)
// no entries means not a dir, so it can never have matches
// foo.txt/** doesn't match foo.txt
if (!entries)
return
// test without the globstar, and with every child both below
// and replacing the globstar.
var remainWithoutGlobStar = remain.slice(1)
var gspref = prefix ? [ prefix ] : []
var noGlobStar = gspref.concat(remainWithoutGlobStar)
// the noGlobStar pattern exits the inGlobStar state
this._process(noGlobStar, index, false)
var len = entries.length
var isSym = this.symlinks[abs]
// If it's a symlink, and we're in a globstar, then stop
if (isSym && inGlobStar)
return
for (var i = 0; i < len; i++) {
var e = entries[i]
if (e.charAt(0) === '.' && !this.dot)
continue
// these two cases enter the inGlobStar state
var instead = gspref.concat(entries[i], remainWithoutGlobStar)
this._process(instead, index, true)
var below = gspref.concat(entries[i], remain)
this._process(below, index, true)
}
}
GlobSync.prototype._processSimple = function (prefix, index) {
// XXX review this. Shouldn't it be doing the mounting etc
// before doing stat? kinda weird?
var exists = this._stat(prefix)
if (!this.matches[index])
this.matches[index] = Object.create(null)
// If it doesn't exist, then just mark the lack of results
if (!exists)
return
if (prefix && isAbsolute(prefix) && !this.nomount) {
var trail = /[\/\\]$/.test(prefix)
if (prefix.charAt(0) === '/') {
prefix = path.join(this.root, prefix)
} else {
prefix = path.resolve(this.root, prefix)
if (trail)
prefix += '/'
}
}
if (process.platform === 'win32')
prefix = prefix.replace(/\\/g, '/')
// Mark this as a match
this._emitMatch(index, prefix)
}
// Returns either 'DIR', 'FILE', or false
GlobSync.prototype._stat = function (f) {
var abs = this._makeAbs(f)
var needDir = f.slice(-1) === '/'
if (f.length > this.maxLength)
return false
if (!this.stat && ownProp(this.cache, abs)) {
var c = this.cache[abs]
if (Array.isArray(c))
c = 'DIR'
// It exists, but maybe not how we need it
if (!needDir || c === 'DIR')
return c
if (needDir && c === 'FILE')
return false
// otherwise we have to stat, because maybe c=true
// if we know it exists, but not what it is.
}
var exists
var stat = this.statCache[abs]
if (!stat) {
var lstat
try {
lstat = this.fs.lstatSync(abs)
} catch (er) {
if (er && (er.code === 'ENOENT' || er.code === 'ENOTDIR')) {
this.statCache[abs] = false
return false
}
}
if (lstat && lstat.isSymbolicLink()) {
try {
stat = this.fs.statSync(abs)
} catch (er) {
stat = lstat
}
} else {
stat = lstat
}
}
this.statCache[abs] = stat
var c = true
if (stat)
c = stat.isDirectory() ? 'DIR' : 'FILE'
this.cache[abs] = this.cache[abs] || c
if (needDir && c === 'FILE')
return false
return c
}
GlobSync.prototype._mark = function (p) {
return common.mark(this, p)
}
GlobSync.prototype._makeAbs = function (f) {
return common.makeAbs(this, f)
}
-15
View File
@@ -1,15 +0,0 @@
The ISC License
Copyright (c) Isaac Z. Schlueter, Ben Noordhuis, and Contributors
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-143
View File
@@ -1,143 +0,0 @@
# graceful-fs
graceful-fs functions as a drop-in replacement for the fs module,
making various improvements.
The improvements are meant to normalize behavior across different
platforms and environments, and to make filesystem access more
resilient to errors.
## Improvements over [fs module](https://nodejs.org/api/fs.html)
* Queues up `open` and `readdir` calls, and retries them once
something closes if there is an EMFILE error from too many file
descriptors.
* fixes `lchmod` for Node versions prior to 0.6.2.
* implements `fs.lutimes` if possible. Otherwise it becomes a noop.
* ignores `EINVAL` and `EPERM` errors in `chown`, `fchown` or
`lchown` if the user isn't root.
* makes `lchmod` and `lchown` become noops, if not available.
* retries reading a file if `read` results in EAGAIN error.
On Windows, it retries renaming a file for up to one second if `EACCESS`
or `EPERM` error occurs, likely because antivirus software has locked
the directory.
## USAGE
```javascript
// use just like fs
var fs = require('graceful-fs')
// now go and do stuff with it...
fs.readFile('some-file-or-whatever', (err, data) => {
// Do stuff here.
})
```
## Sync methods
This module cannot intercept or handle `EMFILE` or `ENFILE` errors from sync
methods. If you use sync methods which open file descriptors then you are
responsible for dealing with any errors.
This is a known limitation, not a bug.
## Global Patching
If you want to patch the global fs module (or any other fs-like
module) you can do this:
```javascript
// Make sure to read the caveat below.
var realFs = require('fs')
var gracefulFs = require('graceful-fs')
gracefulFs.gracefulify(realFs)
```
This should only ever be done at the top-level application layer, in
order to delay on EMFILE errors from any fs-using dependencies. You
should **not** do this in a library, because it can cause unexpected
delays in other parts of the program.
## Changes
This module is fairly stable at this point, and used by a lot of
things. That being said, because it implements a subtle behavior
change in a core part of the node API, even modest changes can be
extremely breaking, and the versioning is thus biased towards
bumping the major when in doubt.
The main change between major versions has been switching between
providing a fully-patched `fs` module vs monkey-patching the node core
builtin, and the approach by which a non-monkey-patched `fs` was
created.
The goal is to trade `EMFILE` errors for slower fs operations. So, if
you try to open a zillion files, rather than crashing, `open`
operations will be queued up and wait for something else to `close`.
There are advantages to each approach. Monkey-patching the fs means
that no `EMFILE` errors can possibly occur anywhere in your
application, because everything is using the same core `fs` module,
which is patched. However, it can also obviously cause undesirable
side-effects, especially if the module is loaded multiple times.
Implementing a separate-but-identical patched `fs` module is more
surgical (and doesn't run the risk of patching multiple times), but
also imposes the challenge of keeping in sync with the core module.
The current approach loads the `fs` module, and then creates a
lookalike object that has all the same methods, except a few that are
patched. It is safe to use in all versions of Node from 0.8 through
7.0.
### v4
* Do not monkey-patch the fs module. This module may now be used as a
drop-in dep, and users can opt into monkey-patching the fs builtin
if their app requires it.
### v3
* Monkey-patch fs, because the eval approach no longer works on recent
node.
* fixed possible type-error throw if rename fails on windows
* verify that we *never* get EMFILE errors
* Ignore ENOSYS from chmod/chown
* clarify that graceful-fs must be used as a drop-in
### v2.1.0
* Use eval rather than monkey-patching fs.
* readdir: Always sort the results
* win32: requeue a file if error has an OK status
### v2.0
* A return to monkey patching
* wrap process.cwd
### v1.1
* wrap readFile
* Wrap fs.writeFile.
* readdir protection
* Don't clobber the fs builtin
* Handle fs.read EAGAIN errors by trying again
* Expose the curOpen counter
* No-op lchown/lchmod if not implemented
* fs.rename patch only for win32
* Patch fs.rename to handle AV software on Windows
* Close #4 Chown should not fail on einval or eperm if non-root
* Fix isaacs/fstream#1 Only wrap fs one time
* Fix #3 Start at 1024 max files, then back off on EMFILE
* lutimes that doens't blow up on Linux
* A full on-rewrite using a queue instead of just swallowing the EMFILE error
* Wrap Read/Write streams as well
### 1.0
* Update engines for node 0.6
* Be lstat-graceful on Windows
* first
-23
View File
@@ -1,23 +0,0 @@
'use strict'
module.exports = clone
var getPrototypeOf = Object.getPrototypeOf || function (obj) {
return obj.__proto__
}
function clone (obj) {
if (obj === null || typeof obj !== 'object')
return obj
if (obj instanceof Object)
var copy = { __proto__: getPrototypeOf(obj) }
else
var copy = Object.create(null)
Object.getOwnPropertyNames(obj).forEach(function (key) {
Object.defineProperty(copy, key, Object.getOwnPropertyDescriptor(obj, key))
})
return copy
}
@@ -1,429 +0,0 @@
var fs = require('fs')
var polyfills = require('./polyfills.js')
var legacy = require('./legacy-streams.js')
var clone = require('./clone.js')
var util = require('util')
/* istanbul ignore next - node 0.x polyfill */
var gracefulQueue
var previousSymbol
/* istanbul ignore else - node 0.x polyfill */
if (typeof Symbol === 'function' && typeof Symbol.for === 'function') {
gracefulQueue = Symbol.for('graceful-fs.queue')
// This is used in testing by future versions
previousSymbol = Symbol.for('graceful-fs.previous')
} else {
gracefulQueue = '___graceful-fs.queue'
previousSymbol = '___graceful-fs.previous'
}
function noop () {}
function publishQueue(context, queue) {
Object.defineProperty(context, gracefulQueue, {
get: function() {
return queue
}
})
}
var debug = noop
if (util.debuglog)
debug = util.debuglog('gfs4')
else if (/\bgfs4\b/i.test(process.env.NODE_DEBUG || ''))
debug = function() {
var m = util.format.apply(util, arguments)
m = 'GFS4: ' + m.split(/\n/).join('\nGFS4: ')
console.error(m)
}
// Once time initialization
if (!fs[gracefulQueue]) {
// This queue can be shared by multiple loaded instances
var queue = global[gracefulQueue] || []
publishQueue(fs, queue)
// Patch fs.close/closeSync to shared queue version, because we need
// to retry() whenever a close happens *anywhere* in the program.
// This is essential when multiple graceful-fs instances are
// in play at the same time.
fs.close = (function (fs$close) {
function close (fd, cb) {
return fs$close.call(fs, fd, function (err) {
// This function uses the graceful-fs shared queue
if (!err) {
resetQueue()
}
if (typeof cb === 'function')
cb.apply(this, arguments)
})
}
Object.defineProperty(close, previousSymbol, {
value: fs$close
})
return close
})(fs.close)
fs.closeSync = (function (fs$closeSync) {
function closeSync (fd) {
// This function uses the graceful-fs shared queue
fs$closeSync.apply(fs, arguments)
resetQueue()
}
Object.defineProperty(closeSync, previousSymbol, {
value: fs$closeSync
})
return closeSync
})(fs.closeSync)
if (/\bgfs4\b/i.test(process.env.NODE_DEBUG || '')) {
process.on('exit', function() {
debug(fs[gracefulQueue])
require('assert').equal(fs[gracefulQueue].length, 0)
})
}
}
if (!global[gracefulQueue]) {
publishQueue(global, fs[gracefulQueue]);
}
module.exports = patch(clone(fs))
if (process.env.TEST_GRACEFUL_FS_GLOBAL_PATCH && !fs.__patched) {
module.exports = patch(fs)
fs.__patched = true;
}
function patch (fs) {
// Everything that references the open() function needs to be in here
polyfills(fs)
fs.gracefulify = patch
fs.createReadStream = createReadStream
fs.createWriteStream = createWriteStream
var fs$readFile = fs.readFile
fs.readFile = readFile
function readFile (path, options, cb) {
if (typeof options === 'function')
cb = options, options = null
return go$readFile(path, options, cb)
function go$readFile (path, options, cb, startTime) {
return fs$readFile(path, options, function (err) {
if (err && (err.code === 'EMFILE' || err.code === 'ENFILE'))
enqueue([go$readFile, [path, options, cb], err, startTime || Date.now(), Date.now()])
else {
if (typeof cb === 'function')
cb.apply(this, arguments)
}
})
}
}
var fs$writeFile = fs.writeFile
fs.writeFile = writeFile
function writeFile (path, data, options, cb) {
if (typeof options === 'function')
cb = options, options = null
return go$writeFile(path, data, options, cb)
function go$writeFile (path, data, options, cb, startTime) {
return fs$writeFile(path, data, options, function (err) {
if (err && (err.code === 'EMFILE' || err.code === 'ENFILE'))
enqueue([go$writeFile, [path, data, options, cb], err, startTime || Date.now(), Date.now()])
else {
if (typeof cb === 'function')
cb.apply(this, arguments)
}
})
}
}
var fs$appendFile = fs.appendFile
if (fs$appendFile)
fs.appendFile = appendFile
function appendFile (path, data, options, cb) {
if (typeof options === 'function')
cb = options, options = null
return go$appendFile(path, data, options, cb)
function go$appendFile (path, data, options, cb, startTime) {
return fs$appendFile(path, data, options, function (err) {
if (err && (err.code === 'EMFILE' || err.code === 'ENFILE'))
enqueue([go$appendFile, [path, data, options, cb], err, startTime || Date.now(), Date.now()])
else {
if (typeof cb === 'function')
cb.apply(this, arguments)
}
})
}
}
var fs$copyFile = fs.copyFile
if (fs$copyFile)
fs.copyFile = copyFile
function copyFile (src, dest, flags, cb) {
if (typeof flags === 'function') {
cb = flags
flags = 0
}
return go$copyFile(src, dest, flags, cb)
function go$copyFile (src, dest, flags, cb, startTime) {
return fs$copyFile(src, dest, flags, function (err) {
if (err && (err.code === 'EMFILE' || err.code === 'ENFILE'))
enqueue([go$copyFile, [src, dest, flags, cb], err, startTime || Date.now(), Date.now()])
else {
if (typeof cb === 'function')
cb.apply(this, arguments)
}
})
}
}
var fs$readdir = fs.readdir
fs.readdir = readdir
function readdir (path, options, cb) {
if (typeof options === 'function')
cb = options, options = null
return go$readdir(path, options, cb)
function go$readdir (path, options, cb, startTime) {
return fs$readdir(path, options, function (err, files) {
if (err && (err.code === 'EMFILE' || err.code === 'ENFILE'))
enqueue([go$readdir, [path, options, cb], err, startTime || Date.now(), Date.now()])
else {
if (files && files.sort)
files.sort()
if (typeof cb === 'function')
cb.call(this, err, files)
}
})
}
}
if (process.version.substr(0, 4) === 'v0.8') {
var legStreams = legacy(fs)
ReadStream = legStreams.ReadStream
WriteStream = legStreams.WriteStream
}
var fs$ReadStream = fs.ReadStream
if (fs$ReadStream) {
ReadStream.prototype = Object.create(fs$ReadStream.prototype)
ReadStream.prototype.open = ReadStream$open
}
var fs$WriteStream = fs.WriteStream
if (fs$WriteStream) {
WriteStream.prototype = Object.create(fs$WriteStream.prototype)
WriteStream.prototype.open = WriteStream$open
}
Object.defineProperty(fs, 'ReadStream', {
get: function () {
return ReadStream
},
set: function (val) {
ReadStream = val
},
enumerable: true,
configurable: true
})
Object.defineProperty(fs, 'WriteStream', {
get: function () {
return WriteStream
},
set: function (val) {
WriteStream = val
},
enumerable: true,
configurable: true
})
// legacy names
var FileReadStream = ReadStream
Object.defineProperty(fs, 'FileReadStream', {
get: function () {
return FileReadStream
},
set: function (val) {
FileReadStream = val
},
enumerable: true,
configurable: true
})
var FileWriteStream = WriteStream
Object.defineProperty(fs, 'FileWriteStream', {
get: function () {
return FileWriteStream
},
set: function (val) {
FileWriteStream = val
},
enumerable: true,
configurable: true
})
function ReadStream (path, options) {
if (this instanceof ReadStream)
return fs$ReadStream.apply(this, arguments), this
else
return ReadStream.apply(Object.create(ReadStream.prototype), arguments)
}
function ReadStream$open () {
var that = this
open(that.path, that.flags, that.mode, function (err, fd) {
if (err) {
if (that.autoClose)
that.destroy()
that.emit('error', err)
} else {
that.fd = fd
that.emit('open', fd)
that.read()
}
})
}
function WriteStream (path, options) {
if (this instanceof WriteStream)
return fs$WriteStream.apply(this, arguments), this
else
return WriteStream.apply(Object.create(WriteStream.prototype), arguments)
}
function WriteStream$open () {
var that = this
open(that.path, that.flags, that.mode, function (err, fd) {
if (err) {
that.destroy()
that.emit('error', err)
} else {
that.fd = fd
that.emit('open', fd)
}
})
}
function createReadStream (path, options) {
return new fs.ReadStream(path, options)
}
function createWriteStream (path, options) {
return new fs.WriteStream(path, options)
}
var fs$open = fs.open
fs.open = open
function open (path, flags, mode, cb) {
if (typeof mode === 'function')
cb = mode, mode = null
return go$open(path, flags, mode, cb)
function go$open (path, flags, mode, cb, startTime) {
return fs$open(path, flags, mode, function (err, fd) {
if (err && (err.code === 'EMFILE' || err.code === 'ENFILE'))
enqueue([go$open, [path, flags, mode, cb], err, startTime || Date.now(), Date.now()])
else {
if (typeof cb === 'function')
cb.apply(this, arguments)
}
})
}
}
return fs
}
function enqueue (elem) {
debug('ENQUEUE', elem[0].name, elem[1])
fs[gracefulQueue].push(elem)
retry()
}
// keep track of the timeout between retry() calls
var retryTimer
// reset the startTime and lastTime to now
// this resets the start of the 60 second overall timeout as well as the
// delay between attempts so that we'll retry these jobs sooner
function resetQueue () {
var now = Date.now()
for (var i = 0; i < fs[gracefulQueue].length; ++i) {
// entries that are only a length of 2 are from an older version, don't
// bother modifying those since they'll be retried anyway.
if (fs[gracefulQueue][i].length > 2) {
fs[gracefulQueue][i][3] = now // startTime
fs[gracefulQueue][i][4] = now // lastTime
}
}
// call retry to make sure we're actively processing the queue
retry()
}
function retry () {
// clear the timer and remove it to help prevent unintended concurrency
clearTimeout(retryTimer)
retryTimer = undefined
if (fs[gracefulQueue].length === 0)
return
var elem = fs[gracefulQueue].shift()
var fn = elem[0]
var args = elem[1]
// these items may be unset if they were added by an older graceful-fs
var err = elem[2]
var startTime = elem[3]
var lastTime = elem[4]
// if we don't have a startTime we have no way of knowing if we've waited
// long enough, so go ahead and retry this item now
if (startTime === undefined) {
debug('RETRY', fn.name, args)
fn.apply(null, args)
} else if (Date.now() - startTime >= 60000) {
// it's been more than 60 seconds total, bail now
debug('TIMEOUT', fn.name, args)
var cb = args.pop()
if (typeof cb === 'function')
cb.call(null, err)
} else {
// the amount of time between the last attempt and right now
var sinceAttempt = Date.now() - lastTime
// the amount of time between when we first tried, and when we last tried
// rounded up to at least 1
var sinceStart = Math.max(lastTime - startTime, 1)
// backoff. wait longer than the total time we've been retrying, but only
// up to a maximum of 100ms
var desiredDelay = Math.min(sinceStart * 1.2, 100)
// it's been long enough since the last retry, do it again
if (sinceAttempt >= desiredDelay) {
debug('RETRY', fn.name, args)
fn.apply(null, args.concat([startTime]))
} else {
// if we can't do this job yet, push it to the end of the queue
// and let the next iteration check again
fs[gracefulQueue].push(elem)
}
}
// schedule our next run if one isn't already scheduled
if (retryTimer === undefined) {
retryTimer = setTimeout(retry, 0)
}
}
@@ -1,118 +0,0 @@
var Stream = require('stream').Stream
module.exports = legacy
function legacy (fs) {
return {
ReadStream: ReadStream,
WriteStream: WriteStream
}
function ReadStream (path, options) {
if (!(this instanceof ReadStream)) return new ReadStream(path, options);
Stream.call(this);
var self = this;
this.path = path;
this.fd = null;
this.readable = true;
this.paused = false;
this.flags = 'r';
this.mode = 438; /*=0666*/
this.bufferSize = 64 * 1024;
options = options || {};
// Mixin options into this
var keys = Object.keys(options);
for (var index = 0, length = keys.length; index < length; index++) {
var key = keys[index];
this[key] = options[key];
}
if (this.encoding) this.setEncoding(this.encoding);
if (this.start !== undefined) {
if ('number' !== typeof this.start) {
throw TypeError('start must be a Number');
}
if (this.end === undefined) {
this.end = Infinity;
} else if ('number' !== typeof this.end) {
throw TypeError('end must be a Number');
}
if (this.start > this.end) {
throw new Error('start must be <= end');
}
this.pos = this.start;
}
if (this.fd !== null) {
process.nextTick(function() {
self._read();
});
return;
}
fs.open(this.path, this.flags, this.mode, function (err, fd) {
if (err) {
self.emit('error', err);
self.readable = false;
return;
}
self.fd = fd;
self.emit('open', fd);
self._read();
})
}
function WriteStream (path, options) {
if (!(this instanceof WriteStream)) return new WriteStream(path, options);
Stream.call(this);
this.path = path;
this.fd = null;
this.writable = true;
this.flags = 'w';
this.encoding = 'binary';
this.mode = 438; /*=0666*/
this.bytesWritten = 0;
options = options || {};
// Mixin options into this
var keys = Object.keys(options);
for (var index = 0, length = keys.length; index < length; index++) {
var key = keys[index];
this[key] = options[key];
}
if (this.start !== undefined) {
if ('number' !== typeof this.start) {
throw TypeError('start must be a Number');
}
if (this.start < 0) {
throw new Error('start must be >= zero');
}
this.pos = this.start;
}
this.busy = false;
this._queue = [];
if (this.fd === null) {
this._open = fs.open;
this._queue.push([this._open, this.path, this.flags, this.mode, undefined]);
this.flush();
}
}
}
@@ -1,50 +0,0 @@
{
"name": "graceful-fs",
"description": "A drop-in replacement for fs, making various improvements.",
"version": "4.2.8",
"repository": {
"type": "git",
"url": "https://github.com/isaacs/node-graceful-fs"
},
"main": "graceful-fs.js",
"directories": {
"test": "test"
},
"scripts": {
"preversion": "npm test",
"postversion": "npm publish",
"postpublish": "git push origin --follow-tags",
"test": "nyc --silent node test.js | tap -c -",
"posttest": "nyc report"
},
"keywords": [
"fs",
"module",
"reading",
"retry",
"retries",
"queue",
"error",
"errors",
"handling",
"EMFILE",
"EAGAIN",
"EINVAL",
"EPERM",
"EACCESS"
],
"license": "ISC",
"devDependencies": {
"import-fresh": "^2.0.0",
"mkdirp": "^0.5.0",
"rimraf": "^2.2.8",
"tap": "^12.7.0"
},
"files": [
"fs.js",
"graceful-fs.js",
"legacy-streams.js",
"polyfills.js",
"clone.js"
]
}
-346
View File
@@ -1,346 +0,0 @@
var constants = require('constants')
var origCwd = process.cwd
var cwd = null
var platform = process.env.GRACEFUL_FS_PLATFORM || process.platform
process.cwd = function() {
if (!cwd)
cwd = origCwd.call(process)
return cwd
}
try {
process.cwd()
} catch (er) {}
// This check is needed until node.js 12 is required
if (typeof process.chdir === 'function') {
var chdir = process.chdir
process.chdir = function (d) {
cwd = null
chdir.call(process, d)
}
if (Object.setPrototypeOf) Object.setPrototypeOf(process.chdir, chdir)
}
module.exports = patch
function patch (fs) {
// (re-)implement some things that are known busted or missing.
// lchmod, broken prior to 0.6.2
// back-port the fix here.
if (constants.hasOwnProperty('O_SYMLINK') &&
process.version.match(/^v0\.6\.[0-2]|^v0\.5\./)) {
patchLchmod(fs)
}
// lutimes implementation, or no-op
if (!fs.lutimes) {
patchLutimes(fs)
}
// https://github.com/isaacs/node-graceful-fs/issues/4
// Chown should not fail on einval or eperm if non-root.
// It should not fail on enosys ever, as this just indicates
// that a fs doesn't support the intended operation.
fs.chown = chownFix(fs.chown)
fs.fchown = chownFix(fs.fchown)
fs.lchown = chownFix(fs.lchown)
fs.chmod = chmodFix(fs.chmod)
fs.fchmod = chmodFix(fs.fchmod)
fs.lchmod = chmodFix(fs.lchmod)
fs.chownSync = chownFixSync(fs.chownSync)
fs.fchownSync = chownFixSync(fs.fchownSync)
fs.lchownSync = chownFixSync(fs.lchownSync)
fs.chmodSync = chmodFixSync(fs.chmodSync)
fs.fchmodSync = chmodFixSync(fs.fchmodSync)
fs.lchmodSync = chmodFixSync(fs.lchmodSync)
fs.stat = statFix(fs.stat)
fs.fstat = statFix(fs.fstat)
fs.lstat = statFix(fs.lstat)
fs.statSync = statFixSync(fs.statSync)
fs.fstatSync = statFixSync(fs.fstatSync)
fs.lstatSync = statFixSync(fs.lstatSync)
// if lchmod/lchown do not exist, then make them no-ops
if (!fs.lchmod) {
fs.lchmod = function (path, mode, cb) {
if (cb) process.nextTick(cb)
}
fs.lchmodSync = function () {}
}
if (!fs.lchown) {
fs.lchown = function (path, uid, gid, cb) {
if (cb) process.nextTick(cb)
}
fs.lchownSync = function () {}
}
// on Windows, A/V software can lock the directory, causing this
// to fail with an EACCES or EPERM if the directory contains newly
// created files. Try again on failure, for up to 60 seconds.
// Set the timeout this long because some Windows Anti-Virus, such as Parity
// bit9, may lock files for up to a minute, causing npm package install
// failures. Also, take care to yield the scheduler. Windows scheduling gives
// CPU to a busy looping process, which can cause the program causing the lock
// contention to be starved of CPU by node, so the contention doesn't resolve.
if (platform === "win32") {
fs.rename = (function (fs$rename) { return function (from, to, cb) {
var start = Date.now()
var backoff = 0;
fs$rename(from, to, function CB (er) {
if (er
&& (er.code === "EACCES" || er.code === "EPERM")
&& Date.now() - start < 60000) {
setTimeout(function() {
fs.stat(to, function (stater, st) {
if (stater && stater.code === "ENOENT")
fs$rename(from, to, CB);
else
cb(er)
})
}, backoff)
if (backoff < 100)
backoff += 10;
return;
}
if (cb) cb(er)
})
}})(fs.rename)
}
// if read() returns EAGAIN, then just try it again.
fs.read = (function (fs$read) {
function read (fd, buffer, offset, length, position, callback_) {
var callback
if (callback_ && typeof callback_ === 'function') {
var eagCounter = 0
callback = function (er, _, __) {
if (er && er.code === 'EAGAIN' && eagCounter < 10) {
eagCounter ++
return fs$read.call(fs, fd, buffer, offset, length, position, callback)
}
callback_.apply(this, arguments)
}
}
return fs$read.call(fs, fd, buffer, offset, length, position, callback)
}
// This ensures `util.promisify` works as it does for native `fs.read`.
if (Object.setPrototypeOf) Object.setPrototypeOf(read, fs$read)
return read
})(fs.read)
fs.readSync = (function (fs$readSync) { return function (fd, buffer, offset, length, position) {
var eagCounter = 0
while (true) {
try {
return fs$readSync.call(fs, fd, buffer, offset, length, position)
} catch (er) {
if (er.code === 'EAGAIN' && eagCounter < 10) {
eagCounter ++
continue
}
throw er
}
}
}})(fs.readSync)
function patchLchmod (fs) {
fs.lchmod = function (path, mode, callback) {
fs.open( path
, constants.O_WRONLY | constants.O_SYMLINK
, mode
, function (err, fd) {
if (err) {
if (callback) callback(err)
return
}
// prefer to return the chmod error, if one occurs,
// but still try to close, and report closing errors if they occur.
fs.fchmod(fd, mode, function (err) {
fs.close(fd, function(err2) {
if (callback) callback(err || err2)
})
})
})
}
fs.lchmodSync = function (path, mode) {
var fd = fs.openSync(path, constants.O_WRONLY | constants.O_SYMLINK, mode)
// prefer to return the chmod error, if one occurs,
// but still try to close, and report closing errors if they occur.
var threw = true
var ret
try {
ret = fs.fchmodSync(fd, mode)
threw = false
} finally {
if (threw) {
try {
fs.closeSync(fd)
} catch (er) {}
} else {
fs.closeSync(fd)
}
}
return ret
}
}
function patchLutimes (fs) {
if (constants.hasOwnProperty("O_SYMLINK")) {
fs.lutimes = function (path, at, mt, cb) {
fs.open(path, constants.O_SYMLINK, function (er, fd) {
if (er) {
if (cb) cb(er)
return
}
fs.futimes(fd, at, mt, function (er) {
fs.close(fd, function (er2) {
if (cb) cb(er || er2)
})
})
})
}
fs.lutimesSync = function (path, at, mt) {
var fd = fs.openSync(path, constants.O_SYMLINK)
var ret
var threw = true
try {
ret = fs.futimesSync(fd, at, mt)
threw = false
} finally {
if (threw) {
try {
fs.closeSync(fd)
} catch (er) {}
} else {
fs.closeSync(fd)
}
}
return ret
}
} else {
fs.lutimes = function (_a, _b, _c, cb) { if (cb) process.nextTick(cb) }
fs.lutimesSync = function () {}
}
}
function chmodFix (orig) {
if (!orig) return orig
return function (target, mode, cb) {
return orig.call(fs, target, mode, function (er) {
if (chownErOk(er)) er = null
if (cb) cb.apply(this, arguments)
})
}
}
function chmodFixSync (orig) {
if (!orig) return orig
return function (target, mode) {
try {
return orig.call(fs, target, mode)
} catch (er) {
if (!chownErOk(er)) throw er
}
}
}
function chownFix (orig) {
if (!orig) return orig
return function (target, uid, gid, cb) {
return orig.call(fs, target, uid, gid, function (er) {
if (chownErOk(er)) er = null
if (cb) cb.apply(this, arguments)
})
}
}
function chownFixSync (orig) {
if (!orig) return orig
return function (target, uid, gid) {
try {
return orig.call(fs, target, uid, gid)
} catch (er) {
if (!chownErOk(er)) throw er
}
}
}
function statFix (orig) {
if (!orig) return orig
// Older versions of Node erroneously returned signed integers for
// uid + gid.
return function (target, options, cb) {
if (typeof options === 'function') {
cb = options
options = null
}
function callback (er, stats) {
if (stats) {
if (stats.uid < 0) stats.uid += 0x100000000
if (stats.gid < 0) stats.gid += 0x100000000
}
if (cb) cb.apply(this, arguments)
}
return options ? orig.call(fs, target, options, callback)
: orig.call(fs, target, callback)
}
}
function statFixSync (orig) {
if (!orig) return orig
// Older versions of Node erroneously returned signed integers for
// uid + gid.
return function (target, options) {
var stats = options ? orig.call(fs, target, options)
: orig.call(fs, target)
if (stats.uid < 0) stats.uid += 0x100000000
if (stats.gid < 0) stats.gid += 0x100000000
return stats;
}
}
// ENOSYS means that the fs doesn't support the op. Just ignore
// that, because it doesn't matter.
//
// if there's no getuid, or if getuid() is something other
// than 0, and the error is EINVAL or EPERM, then just ignore
// it.
//
// This specific case is a silent failure in cp, install, tar,
// and most other unix tools that manage permissions.
//
// When running as root, or if other types of errors are
// encountered, then it's strict.
function chownErOk (er) {
if (!er)
return true
if (er.code === "ENOSYS")
return true
var nonroot = !process.getuid || process.getuid() !== 0
if (nonroot) {
if (er.code === "EINVAL" || er.code === "EPERM")
return true
}
return false
}
}
-15
View File
@@ -1,15 +0,0 @@
The ISC License
Copyright (c) Isaac Z. Schlueter
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-37
View File
@@ -1,37 +0,0 @@
# inflight
Add callbacks to requests in flight to avoid async duplication
## USAGE
```javascript
var inflight = require('inflight')
// some request that does some stuff
function req(key, callback) {
// key is any random string. like a url or filename or whatever.
//
// will return either a falsey value, indicating that the
// request for this key is already in flight, or a new callback
// which when called will call all callbacks passed to inflightk
// with the same key
callback = inflight(key, callback)
// If we got a falsey value back, then there's already a req going
if (!callback) return
// this is where you'd fetch the url or whatever
// callback is also once()-ified, so it can safely be assigned
// to multiple events etc. First call wins.
setTimeout(function() {
callback(null, key)
}, 100)
}
// only assigns a single setTimeout
// when it dings, all cbs get called
req('foo', cb1)
req('foo', cb2)
req('foo', cb3)
req('foo', cb4)
```
-54
View File
@@ -1,54 +0,0 @@
var wrappy = require('wrappy')
var reqs = Object.create(null)
var once = require('once')
module.exports = wrappy(inflight)
function inflight (key, cb) {
if (reqs[key]) {
reqs[key].push(cb)
return null
} else {
reqs[key] = [cb]
return makeres(key)
}
}
function makeres (key) {
return once(function RES () {
var cbs = reqs[key]
var len = cbs.length
var args = slice(arguments)
// XXX It's somewhat ambiguous whether a new callback added in this
// pass should be queued for later execution if something in the
// list of callbacks throws, or if it should just be discarded.
// However, it's such an edge case that it hardly matters, and either
// choice is likely as surprising as the other.
// As it happens, we do go ahead and schedule it for later execution.
try {
for (var i = 0; i < len; i++) {
cbs[i].apply(null, args)
}
} finally {
if (cbs.length > len) {
// added more in the interim.
// de-zalgo, just in case, but don't call again.
cbs.splice(0, len)
process.nextTick(function () {
RES.apply(null, args)
})
} else {
delete reqs[key]
}
}
})
}
function slice (args) {
var length = args.length
var array = []
for (var i = 0; i < length; i++) array[i] = args[i]
return array
}
-29
View File
@@ -1,29 +0,0 @@
{
"name": "inflight",
"version": "1.0.6",
"description": "Add callbacks to requests in flight to avoid async duplication",
"main": "inflight.js",
"files": [
"inflight.js"
],
"dependencies": {
"once": "^1.3.0",
"wrappy": "1"
},
"devDependencies": {
"tap": "^7.1.2"
},
"scripts": {
"test": "tap test.js --100"
},
"repository": {
"type": "git",
"url": "https://github.com/npm/inflight.git"
},
"author": "Isaac Z. Schlueter <i@izs.me> (http://blog.izs.me/)",
"bugs": {
"url": "https://github.com/isaacs/inflight/issues"
},
"homepage": "https://github.com/isaacs/inflight",
"license": "ISC"
}