├── .gitignore ├── builtin ├── sys.js ├── dgram.js ├── dns.js ├── fs.js ├── https.js ├── net.js ├── repl.js ├── tls.js ├── cluster.js ├── module.js ├── readline.js ├── child_process.js ├── process.js ├── _shims.js ├── _stream_passthrough.js ├── _stream_duplex.js ├── timers.js ├── stream.js ├── querystring.js ├── _stream_transform.js └── _stream_writable.js ├── .zuul.yml ├── test ├── browser │ ├── fs-simple.js │ ├── dns-simple.js │ ├── net-simple.js │ ├── tls-simple.js │ ├── repl-simple.js │ ├── dgram-simple.js │ ├── cluster-simple.js │ ├── readline-simple.js │ ├── child-process-simple.js │ ├── tty-simple.js │ ├── process-simple.js │ ├── stream2-readable-wrap-empty.js │ ├── stream2-finish-pipe.js │ ├── stream-pipe-event.js │ ├── stream2-read-sync-stack.js │ ├── timers-simple.js │ ├── stream-push-order.js │ ├── stream2-compatibility.js │ ├── util-inspect.js │ ├── stream-pipe-error-handling.js │ ├── stream2-large-read-stall.js │ ├── events-listeners.js │ ├── stream-push-strings.js │ ├── stream2-readable-non-empty-end.js │ ├── stream2-readable-legacy-drain.js │ ├── stream2-unpipe-leak.js │ ├── stream-readable-flow-recursion.js │ ├── stream2-unpipe-drain.js │ ├── stream-big-push.js │ ├── stream-unshift-empty-chunk.js │ ├── stream2-readable-from-list.js │ ├── stream-pipe-after-end.js │ ├── stream2-pipe-error-handling.js │ ├── util-is.js │ ├── events-remove-listeners.js │ ├── string-decoder-simple.js │ ├── stream2-push.js │ ├── stream2-readable-empty-buffer-no-eof.js │ ├── stream-readable-event.js │ ├── stream-pipe-cleanup.js │ ├── stream-unshift-read-race.js │ ├── stream2-objects.js │ ├── stream2-set-encoding.js │ ├── querystring-simple.js │ ├── path-simple.js │ ├── stream2-writable.js │ ├── stream2-basic.js │ └── stream2-transform.js └── node │ └── node-test.js ├── .travis.yml ├── LICENSE ├── index.js ├── package.json └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /builtin/sys.js: -------------------------------------------------------------------------------- 1 | module.exports = require('util'); 2 | -------------------------------------------------------------------------------- /builtin/dgram.js: -------------------------------------------------------------------------------- 1 | 2 | // not implemented 3 | // The reason for having an empty file and not throwing is to allow 4 | // untraditional implementation of this module. 5 | -------------------------------------------------------------------------------- /builtin/dns.js: -------------------------------------------------------------------------------- 1 | 2 | // not implemented 3 | // The reason for having an empty file and not throwing is to allow 4 | // untraditional implementation of this module. 5 | -------------------------------------------------------------------------------- /builtin/fs.js: -------------------------------------------------------------------------------- 1 | 2 | // not implemented 3 | // The reason for having an empty file and not throwing is to allow 4 | // untraditional implementation of this module. 5 | -------------------------------------------------------------------------------- /builtin/https.js: -------------------------------------------------------------------------------- 1 | 2 | // not implemented 3 | // The reason for having an empty file and not throwing is to allow 4 | // untraditional implementation of this module. 5 | -------------------------------------------------------------------------------- /builtin/net.js: -------------------------------------------------------------------------------- 1 | 2 | // not implemented 3 | // The reason for having an empty file and not throwing is to allow 4 | // untraditional implementation of this module. 5 | -------------------------------------------------------------------------------- /builtin/repl.js: -------------------------------------------------------------------------------- 1 | 2 | // not implemented 3 | // The reason for having an empty file and not throwing is to allow 4 | // untraditional implementation of this module. 5 | -------------------------------------------------------------------------------- /builtin/tls.js: -------------------------------------------------------------------------------- 1 | 2 | // not implemented 3 | // The reason for having an empty file and not throwing is to allow 4 | // untraditional implementation of this module. 5 | -------------------------------------------------------------------------------- /builtin/cluster.js: -------------------------------------------------------------------------------- 1 | 2 | // not implemented 3 | // The reason for having an empty file and not throwing is to allow 4 | // untraditional implementation of this module. 5 | -------------------------------------------------------------------------------- /builtin/module.js: -------------------------------------------------------------------------------- 1 | 2 | // not implemented 3 | // The reason for having an empty file and not throwing is to allow 4 | // untraditional implementation of this module. 5 | -------------------------------------------------------------------------------- /builtin/readline.js: -------------------------------------------------------------------------------- 1 | 2 | // not implemented 3 | // The reason for having an empty file and not throwing is to allow 4 | // untraditional implementation of this module. 5 | -------------------------------------------------------------------------------- /builtin/child_process.js: -------------------------------------------------------------------------------- 1 | 2 | // not implemented 3 | // The reason for having an empty file and not throwing is to allow 4 | // untraditional implementation of this module. 5 | -------------------------------------------------------------------------------- /.zuul.yml: -------------------------------------------------------------------------------- 1 | ui: tape 2 | browsers: 3 | - name: chrome 4 | version: latest 5 | - name: safari 6 | version: latest 7 | - name: ie 8 | version: latest 9 | - name: firefox 10 | version: latest 11 | - name: iphone 12 | version: latest 13 | -------------------------------------------------------------------------------- /test/browser/fs-simple.js: -------------------------------------------------------------------------------- 1 | 2 | var test = require('tape'); 3 | 4 | test('require fs should not throw', function (t) { 5 | try { 6 | var ret = require('fs'); 7 | t.ok(true, 'fs did not throw'); 8 | t.deepEqual(ret, {}); 9 | } catch (e) { 10 | t.ok(false, 'fs did throw'); 11 | } 12 | t.end(); 13 | }); 14 | -------------------------------------------------------------------------------- /test/browser/dns-simple.js: -------------------------------------------------------------------------------- 1 | 2 | var test = require('tape'); 3 | 4 | test('require dns should not throw', function (t) { 5 | try { 6 | var ret = require('dns'); 7 | t.ok(true, 'dns did not throw'); 8 | t.deepEqual(ret, {}); 9 | } catch (e) { 10 | t.ok(false, 'dns did throw'); 11 | } 12 | t.end(); 13 | }); 14 | -------------------------------------------------------------------------------- /test/browser/net-simple.js: -------------------------------------------------------------------------------- 1 | 2 | var test = require('tape'); 3 | 4 | test('require net should not throw', function (t) { 5 | try { 6 | var ret = require('net'); 7 | t.ok(true, 'net did not throw'); 8 | t.deepEqual(ret, {}); 9 | } catch (e) { 10 | t.ok(false, 'net did throw'); 11 | } 12 | t.end(); 13 | }); 14 | -------------------------------------------------------------------------------- /test/browser/tls-simple.js: -------------------------------------------------------------------------------- 1 | 2 | var test = require('tape'); 3 | 4 | test('require tls should not throw', function (t) { 5 | try { 6 | var ret = require('tls'); 7 | t.ok(true, 'tls did not throw'); 8 | t.deepEqual(ret, {}); 9 | } catch (e) { 10 | t.ok(false, 'tls did throw'); 11 | } 12 | t.end(); 13 | }); 14 | -------------------------------------------------------------------------------- /test/browser/repl-simple.js: -------------------------------------------------------------------------------- 1 | 2 | var test = require('tape'); 3 | 4 | test('require repl should not throw', function (t) { 5 | try { 6 | var ret = require('repl'); 7 | t.ok(true, 'repl did not throw'); 8 | t.deepEqual(ret, {}); 9 | } catch (e) { 10 | t.ok(false, 'repl did throw'); 11 | } 12 | t.end(); 13 | }); 14 | -------------------------------------------------------------------------------- /test/browser/dgram-simple.js: -------------------------------------------------------------------------------- 1 | 2 | var test = require('tape'); 3 | 4 | test('require dgram should not throw', function (t) { 5 | try { 6 | var ret = require('dgram'); 7 | t.ok(true, 'dgram did not throw'); 8 | t.deepEqual(ret, {}); 9 | } catch (e) { 10 | t.ok(false, 'dgram did throw'); 11 | } 12 | t.end(); 13 | }); 14 | -------------------------------------------------------------------------------- /test/browser/cluster-simple.js: -------------------------------------------------------------------------------- 1 | 2 | var test = require('tape'); 3 | 4 | test('require cluster should not throw', function (t) { 5 | try { 6 | var ret = require('cluster'); 7 | t.ok(true, 'cluster did not throw'); 8 | t.deepEqual(ret, {}); 9 | } catch (e) { 10 | t.ok(false, 'cluster did throw'); 11 | } 12 | t.end(); 13 | }); 14 | -------------------------------------------------------------------------------- /test/browser/readline-simple.js: -------------------------------------------------------------------------------- 1 | 2 | var test = require('tape'); 3 | 4 | test('require readline should not throw', function (t) { 5 | try { 6 | var ret = require('readline'); 7 | t.ok(true, 'readline did not throw'); 8 | t.deepEqual(ret, {}); 9 | } catch (e) { 10 | t.ok(false, 'readline did throw'); 11 | } 12 | t.end(); 13 | }); 14 | -------------------------------------------------------------------------------- /test/browser/child-process-simple.js: -------------------------------------------------------------------------------- 1 | 2 | var test = require('tape'); 3 | 4 | test('require child_process should not throw', function (t) { 5 | try { 6 | var ret = require('child_process'); 7 | t.ok(true, 'child_process did not throw'); 8 | t.deepEqual(ret, {}); 9 | } catch (e) { 10 | t.ok(false, 'child_process did throw'); 11 | } 12 | t.end(); 13 | }); 14 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - '0.10' 4 | env: 5 | global: 6 | - secure: KWpmXC5NBLCXd/48SbpyZiVMItCg4RBw/hWa9ULA6NKCZzHVYzUaWNrWG+Ecs3+XudDplB5m91jtgPKOKYMONeoTr2MsBelxe1/xeRPTDuPZoj3G2yUi69nqs9f36CSf40/yRm/L8bKAEaeMYzAB4OZZPwEvg0LT/KtKp4E1CUg= 7 | - secure: S+pKJvHKsP2vEECj1pg5033ckoYZJEcJluRjqL4WiBF/Dn6tnXRKyeGM6ZUvZ8zD+QoTeDfkDz9RUoINFB5t26fIwzdMjarnkocSEKROXSlEv3zmG3S+wcKpKmDFX6hsrdNVa+1xCl+7374BhG4cjXTyaZGLXkhLVySElqhexjA= 8 | -------------------------------------------------------------------------------- /builtin/process.js: -------------------------------------------------------------------------------- 1 | var process = module.exports = {}; 2 | 3 | var timers = require('timers'); 4 | process.nextTick = timers.setImmediate; 5 | 6 | process.title = 'browser'; 7 | process.browser = true; 8 | process.env = {}; 9 | process.argv = []; 10 | 11 | process.binding = function (name) { 12 | if (name === 'evals') return (require)('vm') 13 | else throw new Error('No such module. (Possibly not yet loaded)') 14 | }; 15 | 16 | (function () { 17 | var cwd = '/'; 18 | var path; 19 | process.cwd = function () { return cwd }; 20 | process.chdir = function (dir) { 21 | if (!path) path = require('path'); 22 | cwd = path.resolve(dir, cwd); 23 | }; 24 | })(); 25 | -------------------------------------------------------------------------------- /test/browser/tty-simple.js: -------------------------------------------------------------------------------- 1 | 2 | var test = require('tape'); 3 | 4 | var tty = require('tty'); 5 | 6 | test('tty.isatty return false', function (t) { 7 | t.equal(tty.isatty(), false); 8 | t.end(); 9 | }); 10 | 11 | test('tty.ReadStream', function (t) { 12 | try { 13 | new tty.ReadStream(); 14 | t.ok(false, 'tty.ReadStream did not throw'); 15 | } catch (e) { 16 | t.ok(true, 'tty.ReadStream did throw'); 17 | } 18 | t.end(); 19 | }); 20 | 21 | test('tty.WriteStream', function (t) { 22 | try { 23 | new tty.WriteStream(); 24 | t.ok(false, 'tty.WriteStream did not throw'); 25 | } catch (e) { 26 | t.ok(true, 'tty.WriteStream did throw'); 27 | } 28 | t.end(); 29 | }); 30 | -------------------------------------------------------------------------------- /test/browser/process-simple.js: -------------------------------------------------------------------------------- 1 | 2 | var test = require('tape'); 3 | var process = require('process'); 4 | 5 | test('process.nextTick works', function (t) { 6 | process.nextTick(function () { 7 | t.end(); 8 | }); 9 | }); 10 | 11 | test('process.title is browser', function (t) { 12 | t.equal(process.title, 'browser'); 13 | t.end(); 14 | }); 15 | 16 | test('process.env is an empty object', function (t) { 17 | t.deepEqual(process.env, {}); 18 | t.end(); 19 | }); 20 | 21 | test('process.argv is an empty array', function (t) { 22 | t.deepEqual(process.argv, []); 23 | t.end(); 24 | }); 25 | 26 | test('process.cwd returns /', function (t) { 27 | t.equal(process.cwd(), '/'); 28 | t.end(); 29 | }); 30 | -------------------------------------------------------------------------------- /builtin/_shims.js: -------------------------------------------------------------------------------- 1 | 2 | // In IE the description property of an error is visibel 3 | if (new Error().hasOwnProperty('description')) { 4 | var ERROR_PROPERTY_FILTER = function (obj, array) { 5 | if (Object.prototype.toString.call(obj) === '[object Error]') { 6 | array = array.filter(function (name) { 7 | return name !== 'description' && name !== 'number'; 8 | }); 9 | } 10 | return array; 11 | }; 12 | 13 | exports.keys = function (object) { 14 | return ERROR_PROPERTY_FILTER(object, Object.keys(object)); 15 | }; 16 | exports.getOwnPropertyNames = function (object) { 17 | return ERROR_PROPERTY_FILTER(object, Object.getOwnPropertyNames(object)); 18 | }; 19 | } else { 20 | exports.keys = Object.keys; 21 | exports.getOwnPropertyNames = Object.getOwnPropertyNames; 22 | } 23 | -------------------------------------------------------------------------------- /test/node/node-test.js: -------------------------------------------------------------------------------- 1 | 2 | var test = require('tape'); 3 | var builtins = require('../../index.js'); 4 | 5 | test('test that all the modules are set', function (t) { 6 | t.deepEqual(Object.keys(builtins).sort(), [ 7 | '_shims', 8 | '_stream_duplex', 9 | '_stream_passthrough', 10 | '_stream_readable', 11 | '_stream_transform', 12 | '_stream_writable', 13 | 'assert', 14 | 'buffer', 15 | 'child_process', 16 | 'cluster', 17 | 'console', 18 | 'constants', 19 | 'crypto', 20 | 'dgram', 21 | 'dns', 22 | 'domain', 23 | 'events', 24 | 'fs', 25 | 'http', 26 | 'https', 27 | 'module', 28 | 'net', 29 | 'os', 30 | 'path', 31 | 'process', 32 | 'punycode', 33 | 'querystring', 34 | 'readline', 35 | 'repl', 36 | 'stream', 37 | 'string_decoder', 38 | 'sys', 39 | 'timers', 40 | 'tls', 41 | 'tty', 42 | 'url', 43 | 'util', 44 | 'vm', 45 | 'zlib' 46 | ]); 47 | t.end(); 48 | }); 49 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2013 Alex Gorbatchev 4 | 5 | Permission is hereby granted, free of charge, 6 | to any person obtaining a copy of this software and 7 | associated documentation files (the "Software"), to 8 | deal in the Software without restriction, including 9 | without limitation the rights to use, copy, modify, 10 | merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom 12 | the Software is furnished to do so, 13 | subject to the following conditions: 14 | 15 | The above copyright notice and this permission notice 16 | shall be included in all copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 19 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 20 | OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 21 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR 22 | ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 23 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 24 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /builtin/_stream_passthrough.js: -------------------------------------------------------------------------------- 1 | // Copyright Joyent, Inc. and other Node contributors. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the 5 | // "Software"), to deal in the Software without restriction, including 6 | // without limitation the rights to use, copy, modify, merge, publish, 7 | // distribute, sublicense, and/or sell copies of the Software, and to permit 8 | // persons to whom the Software is furnished to do so, subject to the 9 | // following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included 12 | // in all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 17 | // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 20 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | // a passthrough stream. 23 | // basically just the most minimal sort of Transform stream. 24 | // Every written chunk gets output as-is. 25 | 26 | module.exports = PassThrough; 27 | 28 | var Transform = require('_stream_transform'); 29 | var util = require('util'); 30 | util.inherits(PassThrough, Transform); 31 | 32 | function PassThrough(options) { 33 | if (!(this instanceof PassThrough)) 34 | return new PassThrough(options); 35 | 36 | Transform.call(this, options); 37 | } 38 | 39 | PassThrough.prototype._transform = function(chunk, encoding, cb) { 40 | cb(null, chunk); 41 | }; 42 | -------------------------------------------------------------------------------- /test/browser/stream2-readable-wrap-empty.js: -------------------------------------------------------------------------------- 1 | // Copyright Joyent, Inc. and other Node contributors. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the 5 | // "Software"), to deal in the Software without restriction, including 6 | // without limitation the rights to use, copy, modify, merge, publish, 7 | // distribute, sublicense, and/or sell copies of the Software, and to permit 8 | // persons to whom the Software is furnished to do so, subject to the 9 | // following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included 12 | // in all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 17 | // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 20 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | var test = require('tape'); 23 | 24 | var Readable = require('stream').Readable; 25 | var EE = require('events').EventEmitter; 26 | 27 | test('stream2 - readable wrap empty', function (t) { 28 | var oldStream = new EE(); 29 | oldStream.pause = function(){}; 30 | oldStream.resume = function(){}; 31 | 32 | var newStream = new Readable().wrap(oldStream); 33 | 34 | var ended = false; 35 | newStream 36 | .on('readable', function(){}) 37 | .on('end', function(){ ended = true; }); 38 | 39 | oldStream.emit('end'); 40 | 41 | function done(){ 42 | t.ok(ended); 43 | t.end(); 44 | } 45 | newStream.on('end', done); 46 | }); -------------------------------------------------------------------------------- /test/browser/stream2-finish-pipe.js: -------------------------------------------------------------------------------- 1 | // Copyright Joyent, Inc. and other Node contributors. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the 5 | // "Software"), to deal in the Software without restriction, including 6 | // without limitation the rights to use, copy, modify, merge, publish, 7 | // distribute, sublicense, and/or sell copies of the Software, and to permit 8 | // persons to whom the Software is furnished to do so, subject to the 9 | // following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included 12 | // in all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 17 | // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 20 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | var test = require('tape'); 23 | var stream = require('stream'); 24 | var Buffer = require('buffer').Buffer; 25 | 26 | test('stream2 - finish pipe', function (t) { 27 | var r = new stream.Readable(); 28 | r._read = function(size) { 29 | r.push(new Buffer(size)); 30 | }; 31 | 32 | var w = new stream.Writable(); 33 | w._write = function(data, encoding, cb) { 34 | cb(null); 35 | }; 36 | 37 | r.pipe(w); 38 | 39 | // This might sound unrealistic, but it happens in net.js. When 40 | // `socket.allowHalfOpen === false`, EOF will cause `.destroySoon()` call which 41 | // ends the writable side of net.Socket. 42 | w.end(); 43 | t.end(); 44 | }); 45 | -------------------------------------------------------------------------------- /test/browser/stream-pipe-event.js: -------------------------------------------------------------------------------- 1 | // Copyright Joyent, Inc. and other Node contributors. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the 5 | // "Software"), to deal in the Software without restriction, including 6 | // without limitation the rights to use, copy, modify, merge, publish, 7 | // distribute, sublicense, and/or sell copies of the Software, and to permit 8 | // persons to whom the Software is furnished to do so, subject to the 9 | // following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included 12 | // in all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 17 | // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 20 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | var stream = require('stream'); 23 | var test = require('tape'); 24 | var util = require('util'); 25 | 26 | test('stream - pipe event', function (t) { 27 | function Writable() { 28 | this.writable = true; 29 | stream.Stream.call(this); 30 | } 31 | util.inherits(Writable, stream.Stream); 32 | 33 | function Readable() { 34 | this.readable = true; 35 | stream.Stream.call(this); 36 | } 37 | util.inherits(Readable, stream.Stream); 38 | 39 | var passed = false; 40 | 41 | var w = new Writable(); 42 | w.on('pipe', function(src) { 43 | passed = true; 44 | }); 45 | 46 | var r = new Readable(); 47 | r.pipe(w); 48 | 49 | t.ok(passed); 50 | t.end(); 51 | }); 52 | -------------------------------------------------------------------------------- /test/browser/stream2-read-sync-stack.js: -------------------------------------------------------------------------------- 1 | // Copyright Joyent, Inc. and other Node contributors. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the 5 | // "Software"), to deal in the Software without restriction, including 6 | // without limitation the rights to use, copy, modify, merge, publish, 7 | // distribute, sublicense, and/or sell copies of the Software, and to permit 8 | // persons to whom the Software is furnished to do so, subject to the 9 | // following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included 12 | // in all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 17 | // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 20 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | var test = require('tape'); 23 | var Buffer = require('buffer').Buffer; 24 | var Readable = require('stream').Readable; 25 | var r = new Readable(); 26 | var N = 256 * 1024; 27 | 28 | test('stream2 - read sync stack', function (t) { 29 | var reads = 0; 30 | r._read = function(n) { 31 | var chunk = reads++ === N ? null : new Buffer(1); 32 | r.push(chunk); 33 | }; 34 | 35 | r.on('readable', function onReadable() { 36 | r.read(N * 2); 37 | }); 38 | 39 | var ended = false; 40 | r.on('end', function onEnd() { 41 | ended = true; 42 | }); 43 | 44 | r.read(0); 45 | 46 | function done() { 47 | t.ok(ended); 48 | t.end(); 49 | } 50 | r.on('end', done); 51 | }); 52 | -------------------------------------------------------------------------------- /test/browser/timers-simple.js: -------------------------------------------------------------------------------- 1 | 2 | var test = require('tape'); 3 | 4 | var timers = require('timers'); 5 | 6 | test('timers.setTimeout - no clear', function (t) { 7 | timers.setTimeout(function () { 8 | t.ok(true, 'callback called'); 9 | t.end(); 10 | }, 1); 11 | }); 12 | 13 | test('timers.setTimeout - clear', function (t) { 14 | var id = timers.setTimeout(function () { 15 | t.ok(false, 'callback called'); 16 | }, 1); 17 | clearTimeout(id); 18 | t.end(); 19 | }); 20 | 21 | test('timers.setInterval - no clear', function (t) { 22 | var id = timers.setInterval(function () { 23 | timers.clearInterval(id); 24 | t.ok(true, 'callback called'); 25 | t.end(); 26 | }, 1); 27 | }); 28 | 29 | test('timers.setInterval - clear', function (t) { 30 | var id = timers.setInterval(function () { 31 | t.ok(false, 'callback called'); 32 | }, 1); 33 | timers.clearInterval(id); 34 | t.end(); 35 | }); 36 | 37 | test('timers.setImmediate - is async', function (t) { 38 | var sync = true; 39 | timers.setImmediate(function () { 40 | t.ok(!sync, 'setImmediate is async'); 41 | t.end(); 42 | }); 43 | sync = false; 44 | }); 45 | 46 | test('timers.setImmediate - no clear', function (t) { 47 | var aCalled = 0, bCalled = 0; 48 | timers.setImmediate(function () { 49 | aCalled += 1; 50 | if (aCalled && bCalled) done(); 51 | }); 52 | timers.setImmediate(function () { 53 | bCalled += 1; 54 | if (aCalled && bCalled) done(); 55 | }); 56 | 57 | function done() { 58 | t.equal(aCalled, 1); 59 | t.equal(bCalled, 1); 60 | t.end(); 61 | } 62 | }); 63 | 64 | test('timers.setImmediate - clear', function (t) { 65 | var aId = timers.setImmediate(function () { 66 | t.ok(false, 'callback called'); 67 | }); 68 | var bId = timers.setImmediate(function () { 69 | t.ok(false, 'callback called'); 70 | }); 71 | timers.clearImmediate(aId); 72 | timers.clearImmediate(bId); 73 | t.end(); 74 | }); 75 | -------------------------------------------------------------------------------- /test/browser/stream-push-order.js: -------------------------------------------------------------------------------- 1 | // Copyright Joyent, Inc. and other Node contributors. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the 5 | // "Software"), to deal in the Software without restriction, including 6 | // without limitation the rights to use, copy, modify, merge, publish, 7 | // distribute, sublicense, and/or sell copies of the Software, and to permit 8 | // persons to whom the Software is furnished to do so, subject to the 9 | // following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included 12 | // in all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 17 | // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 20 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | var Readable = require('stream').Readable; 23 | var test = require('tape'); 24 | 25 | test('stream - push order', function (t) { 26 | var s = new Readable({ 27 | highWaterMark: 20, 28 | encoding: 'ascii' 29 | }); 30 | 31 | var list = ['1', '2', '3', '4', '5', '6']; 32 | 33 | s._read = function (n) { 34 | var one = list.shift(); 35 | if (!one) { 36 | s.push(null); 37 | done(); 38 | } else { 39 | var two = list.shift(); 40 | s.push(one); 41 | s.push(two); 42 | } 43 | }; 44 | 45 | var v = s.read(0); 46 | 47 | // ACTUALLY [1, 3, 5, 6, 4, 2] 48 | 49 | function done() { 50 | t.deepEqual(s._readableState.buffer, 51 | ['1', '2', '3', '4', '5', '6']); 52 | t.end(); 53 | } 54 | }); -------------------------------------------------------------------------------- /test/browser/stream2-compatibility.js: -------------------------------------------------------------------------------- 1 | // Copyright Joyent, Inc. and other Node contributors. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the 5 | // "Software"), to deal in the Software without restriction, including 6 | // without limitation the rights to use, copy, modify, merge, publish, 7 | // distribute, sublicense, and/or sell copies of the Software, and to permit 8 | // persons to whom the Software is furnished to do so, subject to the 9 | // following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included 12 | // in all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 17 | // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 20 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | var R = require('stream').Readable; 23 | var test = require('tape'); 24 | var Buffer = require('buffer').Buffer; 25 | 26 | var util = require('util'); 27 | var EE = require('events').EventEmitter; 28 | 29 | test('stream2 - compatibility', function (t) { 30 | 31 | var ondataCalled = 0; 32 | 33 | function TestReader() { 34 | R.apply(this); 35 | this._buffer = new Buffer(100); 36 | this._buffer.fill('x'); 37 | 38 | this.on('data', function() { 39 | ondataCalled++; 40 | }); 41 | } 42 | 43 | util.inherits(TestReader, R); 44 | 45 | TestReader.prototype._read = function(n) { 46 | this.push(this._buffer); 47 | this._buffer = new Buffer(0); 48 | }; 49 | 50 | var reader = new TestReader(); 51 | t.equal(ondataCalled, 1); 52 | t.end(); 53 | }); -------------------------------------------------------------------------------- /test/browser/util-inspect.js: -------------------------------------------------------------------------------- 1 | // Copyright Joyent, Inc. and other Node contributors. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the 5 | // "Software"), to deal in the Software without restriction, including 6 | // without limitation the rights to use, copy, modify, merge, publish, 7 | // distribute, sublicense, and/or sell copies of the Software, and to permit 8 | // persons to whom the Software is furnished to do so, subject to the 9 | // following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included 12 | // in all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 17 | // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 20 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | var test = require('tape'); 23 | 24 | var util = require('util'); 25 | 26 | test('util.inspect - test for sparse array', function (t) { 27 | var a = ['foo', 'bar', 'baz']; 28 | t.equal(util.inspect(a), '[ \'foo\', \'bar\', \'baz\' ]'); 29 | delete a[1]; 30 | t.equal(util.inspect(a), '[ \'foo\', , \'baz\' ]'); 31 | t.equal(util.inspect(a, true), '[ \'foo\', , \'baz\', [length]: 3 ]'); 32 | t.equal(util.inspect(new Array(5)), '[ , , , , ]'); 33 | t.end(); 34 | }); 35 | 36 | test('util.inspect - exceptions should print the error message, not \'{}\'', function (t) { 37 | t.equal(util.inspect(new Error()), '[Error]'); 38 | t.equal(util.inspect(new Error('FAIL')), '[Error: FAIL]'); 39 | t.equal(util.inspect(new TypeError('FAIL')), '[TypeError: FAIL]'); 40 | t.equal(util.inspect(new SyntaxError('FAIL')), '[SyntaxError: FAIL]'); 41 | t.end(); 42 | }); 43 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 2 | var path = require('path'); 3 | 4 | // load core modules from builtin dir 5 | function localModule(name) { 6 | return path.resolve(__dirname, 'builtin', name + '.js'); 7 | } 8 | 9 | // manually add core which are provided by modules 10 | module.exports = { 11 | "console": require.resolve('console-browserify/'), 12 | "constants": require.resolve('constants-browserify/'), 13 | "crypto": require.resolve('crypto-browserify/'), 14 | "http": require.resolve('http-browserify/'), 15 | "buffer": require.resolve('buffer/'), 16 | "os": path.resolve(require.resolve('os-browserify'), '..', 'browser.js'), 17 | "vm": require.resolve('vm-browserify/'), 18 | "zlib": require.resolve('zlib-browserify/'), 19 | "assert": require.resolve('assert/'), 20 | "child_process": localModule('child_process'), 21 | "cluster": localModule('child_process'), 22 | "dgram": localModule('dgram'), 23 | "dns": localModule('dns'), 24 | "domain": require.resolve('domain-browser/'), 25 | "events": require.resolve('events/'), 26 | "fs": localModule('fs'), 27 | "https": localModule('https'), 28 | "module": localModule('module'), 29 | "net": localModule('net'), 30 | "path": require.resolve('path-browserify/'), 31 | "process": path.resolve(require.resolve('process/'), '..', 'browser.js'), 32 | "punycode": require.resolve('punycode/'), 33 | "querystring": localModule('querystring'), 34 | "readline": localModule('readline'), 35 | "repl": localModule('repl'), 36 | "stream": localModule('stream'), 37 | "string_decoder": require.resolve('string_decoder/'), 38 | "sys": localModule('sys'), 39 | "timers": localModule('timers'), 40 | "tls": localModule('tls'), 41 | "tty": require.resolve('tty-browserify/'), 42 | "url": localModule('url'), 43 | "util": localModule('util'), 44 | "_shims": localModule('_shims'), 45 | "_stream_duplex": localModule('_stream_duplex'), 46 | "_stream_readable": localModule('_stream_readable'), 47 | "_stream_writable": localModule('_stream_writable'), 48 | "_stream_transform": localModule('_stream_transform'), 49 | "_stream_passthrough": localModule('_stream_passthrough') 50 | }; 51 | -------------------------------------------------------------------------------- /test/browser/stream-pipe-error-handling.js: -------------------------------------------------------------------------------- 1 | // Copyright Joyent, Inc. and other Node contributors. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the 5 | // "Software"), to deal in the Software without restriction, including 6 | // without limitation the rights to use, copy, modify, merge, publish, 7 | // distribute, sublicense, and/or sell copies of the Software, and to permit 8 | // persons to whom the Software is furnished to do so, subject to the 9 | // following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included 12 | // in all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 17 | // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 20 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | var test = require('tape'); 23 | var Stream = require('stream').Stream; 24 | 25 | test('stream - pipe error handling - error listener catches', function (t) { 26 | var source = new Stream(); 27 | var dest = new Stream(); 28 | 29 | source.pipe(dest); 30 | 31 | var gotErr = null; 32 | source.on('error', function(err) { 33 | gotErr = err; 34 | }); 35 | 36 | var err = new Error('This stream turned into bacon.'); 37 | source.emit('error', err); 38 | t.strictEqual(gotErr, err); 39 | t.end(); 40 | }); 41 | 42 | test('stream - pipe error handling - error without listener throws', function (t) { 43 | var source = new Stream(); 44 | var dest = new Stream(); 45 | 46 | source.pipe(dest); 47 | 48 | var err = new Error('This stream turned into bacon.'); 49 | 50 | var gotErr = null; 51 | try { 52 | source.emit('error', err); 53 | } catch (e) { 54 | gotErr = e; 55 | } 56 | 57 | t.strictEqual(gotErr, err); 58 | t.end(); 59 | }); 60 | -------------------------------------------------------------------------------- /test/browser/stream2-large-read-stall.js: -------------------------------------------------------------------------------- 1 | // Copyright Joyent, Inc. and other Node contributors. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the 5 | // "Software"), to deal in the Software without restriction, including 6 | // without limitation the rights to use, copy, modify, merge, publish, 7 | // distribute, sublicense, and/or sell copies of the Software, and to permit 8 | // persons to whom the Software is furnished to do so, subject to the 9 | // following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included 12 | // in all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 17 | // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 20 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | var test = require('tape'); 23 | var Buffer = require('buffer').Buffer; 24 | var Readable = require('stream').Readable; 25 | 26 | test('stream2 - large read stall', function (t) { 27 | // If everything aligns so that you do a read(n) of exactly the 28 | // remaining buffer, then make sure that 'end' still emits. 29 | 30 | var READSIZE = 100; 31 | var PUSHSIZE = 20; 32 | var PUSHCOUNT = 1000; 33 | var HWM = 50; 34 | 35 | var r = new Readable({ 36 | highWaterMark: HWM 37 | }); 38 | var rs = r._readableState; 39 | 40 | r._read = push; 41 | 42 | r.on('readable', function() { 43 | do { 44 | var ret = r.read(READSIZE); 45 | } while (ret && ret.length === READSIZE); 46 | }); 47 | 48 | var endEmitted = false; 49 | r.on('end', function() { 50 | endEmitted = true; 51 | }); 52 | 53 | var pushes = 0; 54 | function push() { 55 | if (pushes > PUSHCOUNT) 56 | return; 57 | 58 | if (pushes++ === PUSHCOUNT) { 59 | return r.push(null); 60 | } 61 | 62 | if (r.push(new Buffer(PUSHSIZE))) 63 | setTimeout(push); 64 | } 65 | 66 | // start the flow 67 | var ret = r.read(0); 68 | 69 | function done() { 70 | t.equal(pushes, PUSHCOUNT + 1); 71 | t.ok(endEmitted); 72 | t.end(); 73 | } 74 | r.on('end', done); 75 | }); 76 | -------------------------------------------------------------------------------- /test/browser/events-listeners.js: -------------------------------------------------------------------------------- 1 | // Copyright Joyent, Inc. and other Node contributors. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the 5 | // "Software"), to deal in the Software without restriction, including 6 | // without limitation the rights to use, copy, modify, merge, publish, 7 | // distribute, sublicense, and/or sell copies of the Software, and to permit 8 | // persons to whom the Software is furnished to do so, subject to the 9 | // following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included 12 | // in all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 17 | // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 20 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | var test = require('tape'); 23 | 24 | var events = require('events'); 25 | 26 | function listener() {} 27 | function listener2() {} 28 | 29 | test('listeners with only one item', function (t) { 30 | var e1 = new events.EventEmitter(); 31 | 32 | e1.on('foo', listener); 33 | var fooListeners = e1.listeners('foo'); 34 | t.deepEqual(e1.listeners('foo'), [listener]); 35 | 36 | e1.removeAllListeners('foo'); 37 | t.deepEqual(e1.listeners('foo'), []); 38 | t.deepEqual(fooListeners, [listener]); 39 | 40 | t.end(); 41 | }); 42 | 43 | test('listeners is a copy', function (t) { 44 | var e2 = new events.EventEmitter(); 45 | 46 | e2.on('foo', listener); 47 | var e2ListenersCopy = e2.listeners('foo'); 48 | t.deepEqual(e2ListenersCopy, [listener]); 49 | t.deepEqual(e2.listeners('foo'), [listener]); 50 | 51 | e2ListenersCopy.push(listener2); 52 | t.deepEqual(e2.listeners('foo'), [listener]); 53 | t.deepEqual(e2ListenersCopy, [listener, listener2]); 54 | 55 | t.end(); 56 | }); 57 | 58 | test('listeners with two items', function (t) { 59 | var e3 = new events.EventEmitter(); 60 | 61 | e3.on('foo', listener); 62 | var e3ListenersCopy = e3.listeners('foo'); 63 | e3.on('foo', listener2); 64 | t.deepEqual(e3.listeners('foo'), [listener, listener2]); 65 | t.deepEqual(e3ListenersCopy, [listener]); 66 | 67 | t.end(); 68 | }); -------------------------------------------------------------------------------- /test/browser/stream-push-strings.js: -------------------------------------------------------------------------------- 1 | // Copyright Joyent, Inc. and other Node contributors. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the 5 | // "Software"), to deal in the Software without restriction, including 6 | // without limitation the rights to use, copy, modify, merge, publish, 7 | // distribute, sublicense, and/or sell copies of the Software, and to permit 8 | // persons to whom the Software is furnished to do so, subject to the 9 | // following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included 12 | // in all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 17 | // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 20 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | var test = require('tape'); 23 | 24 | var Readable = require('stream').Readable; 25 | var timers = require('timers'); 26 | var util = require('util'); 27 | 28 | test('stream - push strings', function (t) { 29 | util.inherits(MyStream, Readable); 30 | function MyStream(options) { 31 | Readable.call(this, options); 32 | this._chunks = 3; 33 | } 34 | 35 | MyStream.prototype._read = function(n) { 36 | switch (this._chunks--) { 37 | case 0: 38 | return this.push(null); 39 | case 1: 40 | return setTimeout((function() { 41 | this.push('last chunk'); 42 | }).bind(this), 100); 43 | case 2: 44 | return this.push('second to last chunk'); 45 | case 3: 46 | return timers.setImmediate((function() { 47 | this.push('first chunk'); 48 | }).bind(this)); 49 | default: 50 | throw new Error('?'); 51 | } 52 | }; 53 | 54 | var ms = new MyStream(); 55 | var results = []; 56 | ms.on('readable', function() { 57 | var chunk; 58 | while (null !== (chunk = ms.read())) 59 | results.push(chunk + ''); 60 | }); 61 | 62 | var expect = [ 'first chunksecond to last chunk', 'last chunk' ]; 63 | function done() { 64 | t.equal(ms._chunks, -1); 65 | t.deepEqual(results, expect); 66 | t.end(); 67 | } 68 | ms.once('end', done); 69 | }); 70 | -------------------------------------------------------------------------------- /test/browser/stream2-readable-non-empty-end.js: -------------------------------------------------------------------------------- 1 | // Copyright Joyent, Inc. and other Node contributors. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the 5 | // "Software"), to deal in the Software without restriction, including 6 | // without limitation the rights to use, copy, modify, merge, publish, 7 | // distribute, sublicense, and/or sell copies of the Software, and to permit 8 | // persons to whom the Software is furnished to do so, subject to the 9 | // following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included 12 | // in all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 17 | // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 20 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | var test = require('tape'); 23 | var Buffer = require('buffer').Buffer; 24 | var Readable = require('stream').Readable; 25 | 26 | test('stream2 - readable non empty end', function (t) { 27 | var len = 0; 28 | var chunks = new Array(10); 29 | for (var i = 1; i <= 10; i++) { 30 | chunks[i-1] = new Buffer(i); 31 | len += i; 32 | } 33 | 34 | var test = new Readable(); 35 | var n = 0; 36 | test._read = function(size) { 37 | var chunk = chunks[n++]; 38 | setTimeout(function() { 39 | test.push(chunk); 40 | }); 41 | }; 42 | 43 | test.on('end', thrower); 44 | function thrower() { 45 | throw new Error('this should not happen!'); 46 | } 47 | 48 | var bytesread = 0; 49 | test.on('readable', function() { 50 | var b = len - bytesread - 1; 51 | var res = test.read(b); 52 | if (res) { 53 | bytesread += res.length; 54 | setTimeout(next); 55 | } 56 | test.read(0); 57 | }); 58 | test.read(0); 59 | 60 | function next() { 61 | // now let's make 'end' happen 62 | test.removeListener('end', thrower); 63 | 64 | var endEmitted = false; 65 | test.on('end', function() { 66 | endEmitted = true; 67 | }); 68 | 69 | // one to get the last byte 70 | var r = test.read(); 71 | t.ok(r); 72 | t.equal(r.length, 1); 73 | r = test.read(); 74 | t.equal(r, null); 75 | t.end(); 76 | } 77 | }); 78 | -------------------------------------------------------------------------------- /test/browser/stream2-readable-legacy-drain.js: -------------------------------------------------------------------------------- 1 | // Copyright Joyent, Inc. and other Node contributors. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the 5 | // "Software"), to deal in the Software without restriction, including 6 | // without limitation the rights to use, copy, modify, merge, publish, 7 | // distribute, sublicense, and/or sell copies of the Software, and to permit 8 | // persons to whom the Software is furnished to do so, subject to the 9 | // following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included 12 | // in all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 17 | // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 20 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | var test = require('tape'); 23 | var Buffer = require('buffer').Buffer; 24 | 25 | var Stream = require('stream'); 26 | var Readable = Stream.Readable; 27 | var timers = require('timers'); 28 | 29 | test('stream2 - readable legacy drain', function (t) { 30 | var r = new Readable(); 31 | var N = 256; 32 | var reads = 0; 33 | r._read = function(n) { 34 | return r.push(++reads === N ? null : new Buffer(1)); 35 | }; 36 | 37 | var rended = false; 38 | r.on('end', function() { 39 | rended = true; 40 | }); 41 | 42 | var w = new Stream(); 43 | w.writable = true; 44 | var writes = 0; 45 | var buffered = 0; 46 | w.write = function(c) { 47 | writes += c.length; 48 | buffered += c.length; 49 | timers.setImmediate(drain); 50 | return false; 51 | }; 52 | 53 | function drain() { 54 | t.ok(buffered <= 2); 55 | buffered = 0; 56 | w.emit('drain'); 57 | } 58 | 59 | 60 | var wended = false; 61 | w.end = function() { 62 | wended = true; 63 | }; 64 | 65 | // Just for kicks, let's mess with the drain count. 66 | // This verifies that even if it gets negative in the 67 | // pipe() cleanup function, we'll still function properly. 68 | r.on('readable', function() { 69 | w.emit('drain'); 70 | }); 71 | 72 | r.pipe(w); 73 | function done() { 74 | t.ok(rended); 75 | t.ok(wended); 76 | t.end(); 77 | } 78 | r.on('end', done); 79 | }); 80 | -------------------------------------------------------------------------------- /test/browser/stream2-unpipe-leak.js: -------------------------------------------------------------------------------- 1 | // Copyright Joyent, Inc. and other Node contributors. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the 5 | // "Software"), to deal in the Software without restriction, including 6 | // without limitation the rights to use, copy, modify, merge, publish, 7 | // distribute, sublicense, and/or sell copies of the Software, and to permit 8 | // persons to whom the Software is furnished to do so, subject to the 9 | // following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included 12 | // in all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 17 | // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 20 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | var test = require('tape'); 23 | var stream = require('stream'); 24 | var Buffer = require('buffer').Buffer; 25 | 26 | var chunk = new Buffer('hallo'); 27 | 28 | var util = require('util'); 29 | 30 | test('stream2 - unpipe leak', function (t) { 31 | function TestWriter() { 32 | stream.Writable.call(this); 33 | } 34 | util.inherits(TestWriter, stream.Writable); 35 | 36 | TestWriter.prototype._write = function(buffer, encoding, callback) { 37 | callback(null); 38 | }; 39 | 40 | var dest = new TestWriter(); 41 | 42 | // Set this high so that we'd trigger a nextTick warning 43 | // and/or RangeError if we do maybeReadMore wrong. 44 | function TestReader() { 45 | stream.Readable.call(this, { highWaterMark: 0x10000 }); 46 | } 47 | util.inherits(TestReader, stream.Readable); 48 | 49 | TestReader.prototype._read = function(size) { 50 | this.push(chunk); 51 | }; 52 | 53 | var src = new TestReader(); 54 | 55 | for (var i = 0; i < 10; i++) { 56 | src.pipe(dest); 57 | src.unpipe(dest); 58 | } 59 | 60 | t.equal(src.listeners('end').length, 0); 61 | t.equal(src.listeners('readable').length, 0); 62 | 63 | t.equal(dest.listeners('unpipe').length, 0); 64 | t.equal(dest.listeners('drain').length, 0); 65 | t.equal(dest.listeners('error').length, 0); 66 | t.equal(dest.listeners('close').length, 0); 67 | t.equal(dest.listeners('finish').length, 0); 68 | 69 | t.end(); 70 | }); 71 | -------------------------------------------------------------------------------- /test/browser/stream-readable-flow-recursion.js: -------------------------------------------------------------------------------- 1 | // Copyright Joyent, Inc. and other Node contributors. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the 5 | // "Software"), to deal in the Software without restriction, including 6 | // without limitation the rights to use, copy, modify, merge, publish, 7 | // distribute, sublicense, and/or sell copies of the Software, and to permit 8 | // persons to whom the Software is furnished to do so, subject to the 9 | // following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included 12 | // in all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 17 | // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 20 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | var test = require('tape'); 23 | var Readable = require('stream').Readable; 24 | var Buffer = require('buffer').Buffer; 25 | 26 | // this test verifies that passing a huge number to read(size) 27 | // will push up the highWaterMark, and cause the stream to read 28 | // more data continuously, but without triggering a nextTick 29 | // warning or RangeError. 30 | 31 | test('stream - readable flow recursion', function (t) { 32 | 33 | var stream = new Readable({ highWaterMark: 2 }); 34 | var reads = 0; 35 | var total = 5000; 36 | stream._read = function(size) { 37 | reads++; 38 | size = Math.min(size, total); 39 | total -= size; 40 | if (size === 0) 41 | stream.push(null); 42 | else 43 | stream.push(new Buffer(size)); 44 | }; 45 | 46 | var depth = 0; 47 | 48 | function flow(stream, size, callback) { 49 | depth += 1; 50 | var chunk = stream.read(size); 51 | 52 | if (!chunk) 53 | stream.once('readable', flow.bind(null, stream, size, callback)); 54 | else 55 | callback(chunk); 56 | 57 | depth -= 1; 58 | } 59 | 60 | flow(stream, 5000, function() { }); 61 | 62 | stream.on('end', function() { 63 | t.equal(reads, 2); 64 | // we pushed up the high water mark 65 | t.equal(stream._readableState.highWaterMark, 8192); 66 | // length is 0 right now, because we pulled it all out. 67 | t.equal(stream._readableState.length, 0); 68 | t.equal(depth, 0); 69 | t.end(); 70 | }); 71 | }); 72 | -------------------------------------------------------------------------------- /builtin/_stream_duplex.js: -------------------------------------------------------------------------------- 1 | // Copyright Joyent, Inc. and other Node contributors. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the 5 | // "Software"), to deal in the Software without restriction, including 6 | // without limitation the rights to use, copy, modify, merge, publish, 7 | // distribute, sublicense, and/or sell copies of the Software, and to permit 8 | // persons to whom the Software is furnished to do so, subject to the 9 | // following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included 12 | // in all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 17 | // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 20 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | // a duplex stream is just a stream that is both readable and writable. 23 | // Since JS doesn't have multiple prototypal inheritance, this class 24 | // prototypally inherits from Readable, and then parasitically from 25 | // Writable. 26 | 27 | module.exports = Duplex; 28 | var util = require('util'); 29 | var timers = require('timers'); 30 | var Readable = require('_stream_readable'); 31 | var Writable = require('_stream_writable'); 32 | 33 | util.inherits(Duplex, Readable); 34 | 35 | Object.keys(Writable.prototype).forEach(function(method) { 36 | if (!Duplex.prototype[method]) 37 | Duplex.prototype[method] = Writable.prototype[method]; 38 | }); 39 | 40 | function Duplex(options) { 41 | if (!(this instanceof Duplex)) 42 | return new Duplex(options); 43 | 44 | Readable.call(this, options); 45 | Writable.call(this, options); 46 | 47 | if (options && options.readable === false) 48 | this.readable = false; 49 | 50 | if (options && options.writable === false) 51 | this.writable = false; 52 | 53 | this.allowHalfOpen = true; 54 | if (options && options.allowHalfOpen === false) 55 | this.allowHalfOpen = false; 56 | 57 | this.once('end', onend); 58 | } 59 | 60 | // the no-half-open enforcer 61 | function onend() { 62 | // if we allow half-open state, or if the writable side ended, 63 | // then we're ok. 64 | if (this.allowHalfOpen || this._writableState.ended) 65 | return; 66 | 67 | // no more data can be written. 68 | // But allow more writes to happen in this tick. 69 | timers.setImmediate(this.end.bind(this)); 70 | } 71 | -------------------------------------------------------------------------------- /test/browser/stream2-unpipe-drain.js: -------------------------------------------------------------------------------- 1 | // Copyright Joyent, Inc. and other Node contributors. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the 5 | // "Software"), to deal in the Software without restriction, including 6 | // without limitation the rights to use, copy, modify, merge, publish, 7 | // distribute, sublicense, and/or sell copies of the Software, and to permit 8 | // persons to whom the Software is furnished to do so, subject to the 9 | // following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included 12 | // in all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 17 | // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 20 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | var test = require('tape'); 23 | var stream = require('stream'); 24 | var timers = require('timers'); 25 | var Buffer = require('buffer').Buffer; 26 | 27 | function randomBytes(size) { 28 | var arr = []; 29 | for (var i = 0; i < size; i++) arr[i] = Math.floor(Math.random() * 256); 30 | return new Buffer(arr); 31 | } 32 | 33 | var util = require('util'); 34 | 35 | test('stream2 - unpipe drain', function (t) { 36 | function TestWriter() { 37 | stream.Writable.call(this); 38 | } 39 | util.inherits(TestWriter, stream.Writable); 40 | 41 | TestWriter.prototype._write = function (buffer, encoding, callback) { 42 | // super slow write stream (callback never called) 43 | }; 44 | 45 | var dest = new TestWriter(); 46 | 47 | function TestReader(id) { 48 | stream.Readable.call(this); 49 | this.reads = 0; 50 | } 51 | util.inherits(TestReader, stream.Readable); 52 | 53 | TestReader.prototype._read = function (size) { 54 | this.reads += 1; 55 | this.push(randomBytes(size)); 56 | }; 57 | 58 | var src1 = new TestReader(); 59 | var src2 = new TestReader(); 60 | 61 | src1.pipe(dest); 62 | 63 | src1.once('readable', function () { 64 | timers.setImmediate(function () { 65 | 66 | src2.pipe(dest); 67 | 68 | src2.once('readable', function () { 69 | timers.setImmediate(function () { 70 | 71 | src1.unpipe(dest); 72 | 73 | done(); 74 | }); 75 | }); 76 | }); 77 | }); 78 | 79 | function done() { 80 | t.equal(src1.reads, 2); 81 | t.equal(src2.reads, 2); 82 | t.end(); 83 | } 84 | }); 85 | -------------------------------------------------------------------------------- /test/browser/stream-big-push.js: -------------------------------------------------------------------------------- 1 | // Copyright Joyent, Inc. and other Node contributors. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the 5 | // "Software"), to deal in the Software without restriction, including 6 | // without limitation the rights to use, copy, modify, merge, publish, 7 | // distribute, sublicense, and/or sell copies of the Software, and to permit 8 | // persons to whom the Software is furnished to do so, subject to the 9 | // following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included 12 | // in all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 17 | // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 20 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | var test = require('tape'); 23 | 24 | var stream = require('stream'); 25 | var str = 'asdfasdfasdfasdfasdf'; 26 | 27 | test('stream.Readable - big push', function (t) { 28 | var r = new stream.Readable({ 29 | highWaterMark: 5, 30 | encoding: 'utf8' 31 | }); 32 | 33 | var reads = 0; 34 | var eofed = false; 35 | var ended = false; 36 | 37 | r._read = function(n) { 38 | if (reads === 0) { 39 | setTimeout(function() { 40 | r.push(str); 41 | }); 42 | reads++; 43 | } else if (reads === 1) { 44 | var ret = r.push(str); 45 | t.equal(ret, false); 46 | reads++; 47 | } else { 48 | t.ok(!eofed); 49 | eofed = true; 50 | r.push(null); 51 | } 52 | }; 53 | 54 | r.on('end', function() { 55 | ended = true; 56 | done(); 57 | }); 58 | 59 | // push some data in to start. 60 | // we've never gotten any read event at this point. 61 | var ret = r.push(str); 62 | // should be false. > hwm 63 | t.ok(!ret); 64 | var chunk = r.read(); 65 | t.equal(chunk, str); 66 | chunk = r.read(); 67 | t.equal(chunk, null); 68 | 69 | r.once('readable', function() { 70 | // this time, we'll get *all* the remaining data, because 71 | // it's been added synchronously, as the read WOULD take 72 | // us below the hwm, and so it triggered a _read() again, 73 | // which synchronously added more, which we then return. 74 | chunk = r.read(); 75 | t.equal(chunk, str + str); 76 | 77 | chunk = r.read(); 78 | t.equal(chunk, null); 79 | }); 80 | 81 | function done() { 82 | t.ok(eofed); 83 | t.ok(ended); 84 | t.equal(reads, 2); 85 | t.end(); 86 | } 87 | }); 88 | -------------------------------------------------------------------------------- /test/browser/stream-unshift-empty-chunk.js: -------------------------------------------------------------------------------- 1 | // Copyright Joyent, Inc. and other Node contributors. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the 5 | // "Software"), to deal in the Software without restriction, including 6 | // without limitation the rights to use, copy, modify, merge, publish, 7 | // distribute, sublicense, and/or sell copies of the Software, and to permit 8 | // persons to whom the Software is furnished to do so, subject to the 9 | // following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included 12 | // in all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 17 | // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 20 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | var test = require('tape'); 23 | var Buffer = require('buffer').Buffer; 24 | 25 | // This test verifies that stream.unshift(Buffer(0)) or 26 | // stream.unshift('') does not set state.reading=false. 27 | var Readable = require('stream').Readable; 28 | 29 | test('stream - unshift empty chunk', function (t) { 30 | var r = new Readable(); 31 | var nChunks = 10; 32 | var chunk = new Buffer(10); 33 | chunk.fill('x'); 34 | 35 | r._read = function(n) { 36 | setTimeout(function() { 37 | r.push(--nChunks === 0 ? null : chunk); 38 | }); 39 | }; 40 | 41 | var readAll = false; 42 | var seen = []; 43 | r.on('readable', function() { 44 | var chunk; 45 | while (chunk = r.read()) { 46 | seen.push(chunk.toString()); 47 | // simulate only reading a certain amount of the data, 48 | // and then putting the rest of the chunk back into the 49 | // stream, like a parser might do. We just fill it with 50 | // 'y' so that it's easy to see which bits were touched, 51 | // and which were not. 52 | var putBack = new Buffer(readAll ? 0 : 5); 53 | putBack.fill('y'); 54 | readAll = !readAll; 55 | r.unshift(putBack); 56 | } 57 | }); 58 | 59 | var expect = 60 | [ 'xxxxxxxxxx', 61 | 'yyyyy', 62 | 'xxxxxxxxxx', 63 | 'yyyyy', 64 | 'xxxxxxxxxx', 65 | 'yyyyy', 66 | 'xxxxxxxxxx', 67 | 'yyyyy', 68 | 'xxxxxxxxxx', 69 | 'yyyyy', 70 | 'xxxxxxxxxx', 71 | 'yyyyy', 72 | 'xxxxxxxxxx', 73 | 'yyyyy', 74 | 'xxxxxxxxxx', 75 | 'yyyyy', 76 | 'xxxxxxxxxx', 77 | 'yyyyy' ]; 78 | 79 | r.on('end', function() { 80 | t.deepEqual(seen, expect); 81 | t.end(); 82 | }); 83 | }); 84 | -------------------------------------------------------------------------------- /test/browser/stream2-readable-from-list.js: -------------------------------------------------------------------------------- 1 | // Copyright Joyent, Inc. and other Node contributors. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the 5 | // "Software"), to deal in the Software without restriction, including 6 | // without limitation the rights to use, copy, modify, merge, publish, 7 | // distribute, sublicense, and/or sell copies of the Software, and to permit 8 | // persons to whom the Software is furnished to do so, subject to the 9 | // following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included 12 | // in all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 17 | // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 20 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | var test = require('tape'); 23 | var Buffer = require('buffer').Buffer; 24 | var fromList = require('stream').Readable._fromList; 25 | 26 | test('buffers', function(t) { 27 | // have a length 28 | var len = 16; 29 | var list = [ new Buffer('foog'), 30 | new Buffer('bark'), 31 | new Buffer('bazy'), 32 | new Buffer('kuel') ]; 33 | 34 | // read more than the first element. 35 | var ret = fromList(6, { buffer: list, length: 16 }); 36 | t.equal(ret.toString(), 'foogba'); 37 | 38 | // read exactly the first element. 39 | ret = fromList(2, { buffer: list, length: 10 }); 40 | t.equal(ret.toString(), 'rk'); 41 | 42 | // read less than the first element. 43 | ret = fromList(2, { buffer: list, length: 8 }); 44 | t.equal(ret.toString(), 'ba'); 45 | 46 | // read more than we have. 47 | ret = fromList(100, { buffer: list, length: 6 }); 48 | t.equal(ret.toString(), 'zykuel'); 49 | 50 | // all consumed. 51 | t.same(list, []); 52 | 53 | t.end(); 54 | }); 55 | 56 | test('strings', function(t) { 57 | // have a length 58 | var len = 16; 59 | var list = [ 'foog', 60 | 'bark', 61 | 'bazy', 62 | 'kuel' ]; 63 | 64 | // read more than the first element. 65 | var ret = fromList(6, { buffer: list, length: 16, decoder: true }); 66 | t.equal(ret, 'foogba'); 67 | 68 | // read exactly the first element. 69 | ret = fromList(2, { buffer: list, length: 10, decoder: true }); 70 | t.equal(ret, 'rk'); 71 | 72 | // read less than the first element. 73 | ret = fromList(2, { buffer: list, length: 8, decoder: true }); 74 | t.equal(ret, 'ba'); 75 | 76 | // read more than we have. 77 | ret = fromList(100, { buffer: list, length: 6, decoder: true }); 78 | t.equal(ret, 'zykuel'); 79 | 80 | // all consumed. 81 | t.same(list, []); 82 | 83 | t.end(); 84 | }); 85 | -------------------------------------------------------------------------------- /test/browser/stream-pipe-after-end.js: -------------------------------------------------------------------------------- 1 | // Copyright Joyent, Inc. and other Node contributors. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the 5 | // "Software"), to deal in the Software without restriction, including 6 | // without limitation the rights to use, copy, modify, merge, publish, 7 | // distribute, sublicense, and/or sell copies of the Software, and to permit 8 | // persons to whom the Software is furnished to do so, subject to the 9 | // following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included 12 | // in all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 17 | // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 20 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | var test = require('tape'); 23 | 24 | var Readable = require('stream').Readable; 25 | var Writable = require('stream').Writable; 26 | var util = require('util'); 27 | 28 | test('stream - pipe after end', function (t) { 29 | util.inherits(TestReadable, Readable); 30 | function TestReadable(opt) { 31 | if (!(this instanceof TestReadable)) 32 | return new TestReadable(opt); 33 | Readable.call(this, opt); 34 | this._ended = false; 35 | } 36 | 37 | TestReadable.prototype._read = function(n) { 38 | if (this._ended) 39 | this.emit('error', new Error('_read called twice')); 40 | this._ended = true; 41 | this.push(null); 42 | }; 43 | 44 | util.inherits(TestWritable, Writable); 45 | function TestWritable(opt) { 46 | if (!(this instanceof TestWritable)) 47 | return new TestWritable(opt); 48 | Writable.call(this, opt); 49 | this._written = []; 50 | } 51 | 52 | TestWritable.prototype._write = function(chunk, encoding, cb) { 53 | this._written.push(chunk); 54 | cb(); 55 | }; 56 | 57 | // this one should not emit 'end' until we read() from it later. 58 | var ender = new TestReadable(); 59 | var enderEnded = false; 60 | 61 | // what happens when you pipe() a Readable that's already ended? 62 | var piper = new TestReadable(); 63 | // pushes EOF null, and length=0, so this will trigger 'end' 64 | piper.read(); 65 | 66 | setTimeout(function() { 67 | ender.on('end', function() { 68 | enderEnded = true; 69 | if (enderEnded && writableFinished) t.end(); 70 | }); 71 | t.ok(!enderEnded); 72 | var c = ender.read(); 73 | t.equal(c, null); 74 | 75 | var w = new TestWritable(); 76 | var writableFinished = false; 77 | w.on('finish', function() { 78 | writableFinished = true; 79 | if (enderEnded && writableFinished) t.end(); 80 | }); 81 | piper.pipe(w); 82 | }); 83 | }); 84 | -------------------------------------------------------------------------------- /test/browser/stream2-pipe-error-handling.js: -------------------------------------------------------------------------------- 1 | // Copyright Joyent, Inc. and other Node contributors. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the 5 | // "Software"), to deal in the Software without restriction, including 6 | // without limitation the rights to use, copy, modify, merge, publish, 7 | // distribute, sublicense, and/or sell copies of the Software, and to permit 8 | // persons to whom the Software is furnished to do so, subject to the 9 | // following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included 12 | // in all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 17 | // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 20 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | var test = require('tape'); 23 | var stream = require('stream'); 24 | var Buffer = require('buffer').Buffer; 25 | 26 | test('stream2 - pipe error handling - error listener catches', function (t) { 27 | var count = 1000; 28 | 29 | var source = new stream.Readable(); 30 | source._read = function(n) { 31 | n = Math.min(count, n); 32 | count -= n; 33 | source.push(new Buffer(n)); 34 | }; 35 | 36 | var unpipedDest; 37 | source.unpipe = function(dest) { 38 | unpipedDest = dest; 39 | stream.Readable.prototype.unpipe.call(this, dest); 40 | }; 41 | 42 | var dest = new stream.Writable(); 43 | dest._write = function(chunk, encoding, cb) { 44 | cb(); 45 | }; 46 | 47 | source.pipe(dest); 48 | 49 | var gotErr = null; 50 | dest.on('error', function(err) { 51 | gotErr = err; 52 | }); 53 | 54 | var unpipedSource; 55 | dest.on('unpipe', function(src) { 56 | unpipedSource = src; 57 | }); 58 | 59 | var err = new Error('This stream turned into bacon.'); 60 | dest.emit('error', err); 61 | t.strictEqual(gotErr, err); 62 | t.strictEqual(unpipedSource, source); 63 | t.strictEqual(unpipedDest, dest); 64 | t.end(); 65 | }); 66 | 67 | test('stream2 - pipe error handling - error listener catches', function (t) { 68 | var count = 1000; 69 | 70 | var source = new stream.Readable(); 71 | source._read = function(n) { 72 | n = Math.min(count, n); 73 | count -= n; 74 | source.push(new Buffer(n)); 75 | }; 76 | 77 | var unpipedDest; 78 | source.unpipe = function(dest) { 79 | unpipedDest = dest; 80 | stream.Readable.prototype.unpipe.call(this, dest); 81 | }; 82 | 83 | var dest = new stream.Writable(); 84 | dest._write = function(chunk, encoding, cb) { 85 | cb(); 86 | }; 87 | 88 | source.pipe(dest); 89 | 90 | var unpipedSource; 91 | dest.on('unpipe', function(src) { 92 | unpipedSource = src; 93 | }); 94 | 95 | var err = new Error('This stream turned into bacon.'); 96 | 97 | var gotErr = null; 98 | try { 99 | dest.emit('error', err); 100 | } catch (e) { 101 | gotErr = e; 102 | } 103 | t.strictEqual(gotErr, err); 104 | t.strictEqual(unpipedSource, source); 105 | t.strictEqual(unpipedDest, dest); 106 | t.end(); 107 | }); 108 | -------------------------------------------------------------------------------- /test/browser/util-is.js: -------------------------------------------------------------------------------- 1 | // Copyright Joyent, Inc. and other Node contributors. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the 5 | // "Software"), to deal in the Software without restriction, including 6 | // without limitation the rights to use, copy, modify, merge, publish, 7 | // distribute, sublicense, and/or sell copies of the Software, and to permit 8 | // persons to whom the Software is furnished to do so, subject to the 9 | // following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included 12 | // in all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 17 | // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 20 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | var test = require('tape'); 23 | 24 | var util = require('util'); 25 | 26 | test('util.isArray', function (t) { 27 | t.equal(true, util.isArray([])); 28 | t.equal(true, util.isArray(Array())); 29 | t.equal(true, util.isArray(new Array())); 30 | t.equal(true, util.isArray(new Array(5))); 31 | t.equal(true, util.isArray(new Array('with', 'some', 'entries'))); 32 | t.equal(false, util.isArray({})); 33 | t.equal(false, util.isArray({ push: function() {} })); 34 | t.equal(false, util.isArray(/regexp/)); 35 | t.equal(false, util.isArray(new Error())); 36 | t.equal(false, util.isArray(Object.create(Array.prototype))); 37 | t.end(); 38 | }); 39 | 40 | test('util.isRegExp', function (t) { 41 | t.equal(true, util.isRegExp(/regexp/)); 42 | t.equal(true, util.isRegExp(RegExp())); 43 | t.equal(true, util.isRegExp(new RegExp())); 44 | t.equal(false, util.isRegExp({})); 45 | t.equal(false, util.isRegExp([])); 46 | t.equal(false, util.isRegExp(new Date())); 47 | t.equal(false, util.isRegExp(Object.create(RegExp.prototype))); 48 | t.end(); 49 | }); 50 | 51 | test('util.isDate', function (t) { 52 | t.equal(true, util.isDate(new Date())); 53 | t.equal(true, util.isDate(new Date(0))); 54 | t.equal(false, util.isDate(Date())); 55 | t.equal(false, util.isDate({})); 56 | t.equal(false, util.isDate([])); 57 | t.equal(false, util.isDate(new Error())); 58 | t.equal(false, util.isDate(Object.create(Date.prototype))); 59 | t.end(); 60 | }); 61 | 62 | test('util.isError', function (t) { 63 | t.equal(true, util.isError(new Error())); 64 | t.equal(true, util.isError(new TypeError())); 65 | t.equal(true, util.isError(new SyntaxError())); 66 | t.equal(false, util.isError({})); 67 | t.equal(false, util.isError({ name: 'Error', message: '' })); 68 | t.equal(false, util.isError([])); 69 | t.equal(false, util.isError(Object.create(Error.prototype))); 70 | t.end(); 71 | }); 72 | 73 | test('util._extend', function (t) { 74 | t.deepEqual(util._extend({a:1}), {a:1}); 75 | t.deepEqual(util._extend({a:1}, []), {a:1}); 76 | t.deepEqual(util._extend({a:1}, null), {a:1}); 77 | t.deepEqual(util._extend({a:1}, true), {a:1}); 78 | t.deepEqual(util._extend({a:1}, false), {a:1}); 79 | t.deepEqual(util._extend({a:1}, {b:2}), {a:1, b:2}); 80 | t.deepEqual(util._extend({a:1, b:2}, {b:3}), {a:1, b:3}); 81 | t.end(); 82 | }); 83 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "browser-builtins", 3 | "version": "3.3.1", 4 | "description": "Builtins that were extracted from node-browser-resolve on which browserify depends", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "tape test/node/*.js && zuul -- ./test/browser/*.js", 8 | "test-local": "zuul --local 9000 -- ./test/browser/*.js" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "git://github.com/alexgorbatchev/node-browser-builtins.git" 13 | }, 14 | "keywords": [ 15 | "resolve", 16 | "browser" 17 | ], 18 | "author": "Alex Gorbatchev ", 19 | "contributors": [ 20 | {"name": "Andreas Madsen", "email": "amwebdk@gmail.com"}, 21 | {"name": "Aria Stewart", "email": "aredridel@nbtsc.org"}, 22 | {"name": "Christian Tellnes", "email": "christian@tellnes.no"}, 23 | {"name": "Danya Postfactum", "email": "danya.postfactum@gmail.com"}, 24 | {"name": "Feross Aboukhadijeh", "email": "feross@feross.org"}, 25 | {"name": "James Halliday", "email": "mail@substack.net"}, 26 | {"name": "Jared Hanson", "email": "jaredhanson@gmail.com"}, 27 | {"name": "Julian Gruber", "email": "julian@juliangruber.com"}, 28 | {"name": "Lance Stout", "email": "lancestout@gmail.com"}, 29 | {"name": "Patrick Mueller", "email": "pmuellr@yahoo.com"}, 30 | {"name": "Victor Powell", "email": "vicapow@gmail.com"} 31 | ], 32 | "license": "MIT", 33 | "dependencies": { 34 | "console-browserify": "~1.1.0", 35 | "constants-browserify": "~0.0.1", 36 | "crypto-browserify": "~3.9.10", 37 | "http-browserify": "~1.7.0", 38 | "buffer": "~3.0.0", 39 | "os-browserify": "~0.1.2", 40 | "vm-browserify": "~0.0.4", 41 | "zlib-browserify": "~0.0.3", 42 | "assert": "~1.3.0", 43 | "domain-browser": "~1.1.2", 44 | "events": "~1.0.1", 45 | "https-browserify": "~0.0.0", 46 | "path-browserify": "~0.0.0", 47 | "string_decoder": "~0.10.0", 48 | "tty-browserify": "~0.0.0", 49 | "process": "~0.10.0", 50 | "punycode": "~1.3.0" 51 | }, 52 | "devDependencies": { 53 | "zuul": "2.1.x", 54 | "tape": "3.5.x" 55 | }, 56 | "browser": { 57 | "console": "console-browserify", 58 | "constants": "constants-browserify", 59 | "crypto": "crypto-browserify", 60 | "http": "http-browserify", 61 | "buffer": "buffer", 62 | "os": "os-browserify", 63 | "vm": "vm-browserify", 64 | "zlib": "zlib-browserify", 65 | "assert": "assert", 66 | "child_process": "./builtin/child_process.js", 67 | "cluster": "./builtin/cluster.js", 68 | "dgram": "./builtin/dgram.js", 69 | "dns": "./builtin/dns.js", 70 | "domain": "domain-browser", 71 | "events": "events", 72 | "fs": "./builtin/fs.js", 73 | "https": "https-browserify", 74 | "module": "./builtin/module.js", 75 | "net": "./builtin/net.js", 76 | "path": "path-browserify", 77 | "process": "process", 78 | "querystring": "./builtin/querystring.js", 79 | "readline": "./builtin/readline.js", 80 | "repl": "./builtin/repl.js", 81 | "stream": "./builtin/stream.js", 82 | "string_decoder": "string_decoder", 83 | "sys": "./builtin/sys.js", 84 | "timers": "./builtin/timers.js", 85 | "tls": "./builtin/tls.js", 86 | "tty": "tty-browserify", 87 | "url": "./builtin/url.js", 88 | "util": "./builtin/util.js", 89 | "_stream_readable": "./builtin/_stream_readable.js", 90 | "_stream_writable": "./builtin/_stream_writable.js", 91 | "_stream_duplex": "./builtin/_stream_duplex.js", 92 | "_stream_transform": "./builtin/_stream_transform.js", 93 | "_stream_passthrough": "./builtin/_stream_passthrough.js" 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /test/browser/events-remove-listeners.js: -------------------------------------------------------------------------------- 1 | // Copyright Joyent, Inc. and other Node contributors. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the 5 | // "Software"), to deal in the Software without restriction, including 6 | // without limitation the rights to use, copy, modify, merge, publish, 7 | // distribute, sublicense, and/or sell copies of the Software, and to permit 8 | // persons to whom the Software is furnished to do so, subject to the 9 | // following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included 12 | // in all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 17 | // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 20 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | var test = require('tape'); 23 | 24 | var events = require('events'); 25 | 26 | var count = 0; 27 | 28 | function listener1() { 29 | count++; 30 | } 31 | 32 | function listener2() { 33 | count++; 34 | } 35 | 36 | function listener3() { 37 | count++; 38 | } 39 | 40 | test('removeListener emits and listeners array becomes empty', function (t) { 41 | var e1 = new events.EventEmitter(); 42 | 43 | var emitted = false; 44 | e1.on('hello', listener1); 45 | e1.on('removeListener', function(name, cb) { 46 | t.equal(name, 'hello'); 47 | t.equal(cb, listener1); 48 | emitted = true; 49 | }); 50 | 51 | e1.removeListener('hello', listener1); 52 | t.deepEqual([], e1.listeners('hello')); 53 | 54 | t.ok(emitted, 'removeListener did fire'); 55 | t.end(); 56 | }); 57 | 58 | test('removeing inactive handler dose nothing', function (t) { 59 | var e2 = new events.EventEmitter(); 60 | 61 | var emitted = false; 62 | e2.on('hello', listener1); 63 | e2.on('removeListener', function () { 64 | emitted = true; 65 | }); 66 | e2.removeListener('hello', listener2); 67 | t.deepEqual([listener1], e2.listeners('hello')); 68 | 69 | t.ok(!emitted, 'removeListener did not fire'); 70 | t.end(); 71 | }); 72 | 73 | test('removeListener only removes one handler', function (t) { 74 | var e3 = new events.EventEmitter(); 75 | 76 | var emitted = false; 77 | e3.on('hello', listener1); 78 | e3.on('hello', listener2); 79 | e3.on('removeListener', function(name, cb) { 80 | emitted = true; 81 | t.equal(name, 'hello'); 82 | t.equal(cb, listener1); 83 | }); 84 | e3.removeListener('hello', listener1); 85 | t.deepEqual([listener2], e3.listeners('hello')); 86 | 87 | t.ok(emitted, 'removeListener did fired'); 88 | t.end(); 89 | }); 90 | 91 | test('regression: removing listener with in removeListener', function (t) { 92 | var e4 = new events.EventEmitter(); 93 | 94 | function remove1() { t.ok(false); } 95 | function remove2() { t.ok(false); } 96 | 97 | var fired = 0; 98 | e4.on('removeListener', function(name, cb) { 99 | fired += 1; 100 | if (cb !== remove1) return; 101 | this.removeListener('quux', remove2); 102 | this.emit('quux'); 103 | }); 104 | e4.on('quux', remove1); 105 | e4.on('quux', remove2); 106 | e4.removeListener('quux', remove1); 107 | 108 | t.equal(fired, 2); 109 | t.end(); 110 | }); 111 | -------------------------------------------------------------------------------- /test/browser/string-decoder-simple.js: -------------------------------------------------------------------------------- 1 | // Copyright Joyent, Inc. and other Node contributors. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the 5 | // "Software"), to deal in the Software without restriction, including 6 | // without limitation the rights to use, copy, modify, merge, publish, 7 | // distribute, sublicense, and/or sell copies of the Software, and to permit 8 | // persons to whom the Software is furnished to do so, subject to the 9 | // following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included 12 | // in all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 17 | // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 20 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | var test = require('tape'); 23 | 24 | var Buffer = require('buffer').Buffer; 25 | var StringDecoder = require('string_decoder').StringDecoder; 26 | 27 | var decoder = new StringDecoder('utf8'); 28 | 29 | test('decoder.write - one byte char', function (t) { 30 | var buffer = new Buffer('$'); 31 | t.deepEqual('$', decoder.write(buffer)); 32 | t.end(); 33 | }); 34 | 35 | test('decoder.write - two byte char', function (t) { 36 | var buffer = new Buffer('¢'); 37 | t.deepEqual('', decoder.write(buffer.slice(0, 1))); 38 | t.deepEqual('¢', decoder.write(buffer.slice(1, 2))); 39 | t.end(); 40 | }); 41 | 42 | test('decoder.write - three byte char', function (t) { 43 | var buffer = new Buffer('€'); 44 | t.deepEqual('', decoder.write(buffer.slice(0, 1))); 45 | t.deepEqual('', decoder.write(buffer.slice(1, 2))); 46 | t.deepEqual('€', decoder.write(buffer.slice(2, 3))); 47 | t.end(); 48 | }); 49 | 50 | 51 | test('decoder.write - four byte char', function (t) { 52 | var buffer = new Buffer([0xF0, 0xA4, 0xAD, 0xA2]); 53 | var s = ''; 54 | s += decoder.write(buffer.slice(0, 1)); 55 | s += decoder.write(buffer.slice(1, 2)); 56 | s += decoder.write(buffer.slice(2, 3)); 57 | s += decoder.write(buffer.slice(3, 4)); 58 | t.ok(s.length > 0); 59 | t.end(); 60 | }); 61 | 62 | test('decoder.write - A mixed ascii and non-ascii string', function (t) { 63 | // Test stolen from deps/v8/test/cctest/test-strings.cc 64 | // U+02E4 -> CB A4 65 | // U+0064 -> 64 66 | // U+12E4 -> E1 8B A4 67 | // U+0030 -> 30 68 | // U+3045 -> E3 81 85 69 | var expected = '\u02e4\u0064\u12e4\u0030\u3045'; 70 | var buffer = new Buffer([0xCB, 0xA4, 0x64, 0xE1, 0x8B, 0xA4, 71 | 0x30, 0xE3, 0x81, 0x85]); 72 | var charLengths = [0, 0, 1, 2, 2, 2, 3, 4, 4, 4, 5, 5]; 73 | 74 | // Split the buffer into 3 segments 75 | // |----|------|-------| 76 | // 0 i j buffer.length 77 | // Scan through every possible 3 segment combination 78 | // and make sure that the string is always parsed. 79 | for (var j = 2; j < buffer.length; j++) { 80 | for (var i = 1; i < j; i++) { 81 | var decoder = new StringDecoder('utf8'); 82 | 83 | var sum = decoder.write(buffer.slice(0, i)); 84 | 85 | // just check that we've received the right amount 86 | // after the first write 87 | t.equal(charLengths[i], sum.length); 88 | 89 | sum += decoder.write(buffer.slice(i, j)); 90 | sum += decoder.write(buffer.slice(j, buffer.length)); 91 | t.equal(expected, sum); 92 | } 93 | } 94 | 95 | t.end(); 96 | }); 97 | -------------------------------------------------------------------------------- /test/browser/stream2-push.js: -------------------------------------------------------------------------------- 1 | // Copyright Joyent, Inc. and other Node contributors. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the 5 | // "Software"), to deal in the Software without restriction, including 6 | // without limitation the rights to use, copy, modify, merge, publish, 7 | // distribute, sublicense, and/or sell copies of the Software, and to permit 8 | // persons to whom the Software is furnished to do so, subject to the 9 | // following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included 12 | // in all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 17 | // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 20 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | var stream = require('stream'); 23 | var Readable = stream.Readable; 24 | var Writable = stream.Writable; 25 | var test = require('tape'); 26 | var timers = require('timers'); 27 | 28 | var EE = require('events').EventEmitter; 29 | 30 | test('stream2 - push', function (t) { 31 | // a mock thing a bit like the net.Socket/tcp_wrap.handle interaction 32 | 33 | var stream = new Readable({ 34 | highWaterMark: 16, 35 | encoding: 'utf8' 36 | }); 37 | 38 | var source = new EE; 39 | 40 | stream._read = function() { 41 | readStart(); 42 | }; 43 | 44 | var ended = false; 45 | stream.on('end', function() { 46 | ended = true; 47 | }); 48 | 49 | source.on('data', function(chunk) { 50 | var ret = stream.push(chunk); 51 | if (!ret) 52 | readStop(); 53 | }); 54 | 55 | source.on('end', function() { 56 | stream.push(null); 57 | }); 58 | 59 | var reading = false; 60 | 61 | function readStart() { 62 | reading = true; 63 | } 64 | 65 | function readStop() { 66 | reading = false; 67 | timers.setImmediate(function() { 68 | var r = stream.read(); 69 | if (r !== null) 70 | writer.write(r); 71 | }); 72 | } 73 | 74 | var writer = new Writable({ 75 | decodeStrings: false 76 | }); 77 | 78 | var written = []; 79 | 80 | var expectWritten = 81 | [ 'asdfgasdfgasdfgasdfg', 82 | 'asdfgasdfgasdfgasdfg', 83 | 'asdfgasdfgasdfgasdfg', 84 | 'asdfgasdfgasdfgasdfg', 85 | 'asdfgasdfgasdfgasdfg', 86 | 'asdfgasdfgasdfgasdfg' ]; 87 | 88 | writer._write = function(chunk, encoding, cb) { 89 | written.push(chunk); 90 | timers.setImmediate(cb); 91 | }; 92 | 93 | writer.on('finish', finish); 94 | 95 | 96 | // now emit some chunks. 97 | 98 | var chunk = "asdfg"; 99 | 100 | var set = 0; 101 | readStart(); 102 | data(); 103 | function data() { 104 | t.ok(reading, 'reading 1'); 105 | source.emit('data', chunk); 106 | t.ok(reading, 'reading 2'); 107 | source.emit('data', chunk); 108 | t.ok(reading, 'reading 3'); 109 | source.emit('data', chunk); 110 | t.ok(reading, 'reading 4'); 111 | source.emit('data', chunk); 112 | t.ok(!reading, 'not reading 5'); 113 | if (set++ < 5) 114 | setTimeout(data, 100); 115 | else 116 | end(); 117 | } 118 | 119 | function finish() { 120 | t.deepEqual(written, expectWritten); 121 | } 122 | 123 | function end() { 124 | source.emit('end'); 125 | t.ok(!reading, 'not reading end'); 126 | writer.end(stream.read()); 127 | setTimeout(function() { 128 | t.ok(ended, 'end emitted'); 129 | t.end(); 130 | }, 100); 131 | } 132 | }); -------------------------------------------------------------------------------- /builtin/timers.js: -------------------------------------------------------------------------------- 1 | try { 2 | // Old IE browsers that do not curry arguments 3 | if (!setTimeout.call) { 4 | var slicer = Array.prototype.slice; 5 | exports.setTimeout = function(fn) { 6 | var args = slicer.call(arguments, 1); 7 | return setTimeout(function() { 8 | return fn.apply(this, args); 9 | }) 10 | }; 11 | 12 | exports.setInterval = function(fn) { 13 | var args = slicer.call(arguments, 1); 14 | return setInterval(function() { 15 | return fn.apply(this, args); 16 | }); 17 | }; 18 | } else { 19 | exports.setTimeout = setTimeout; 20 | exports.setInterval = setInterval; 21 | } 22 | exports.clearTimeout = clearTimeout; 23 | exports.clearInterval = clearInterval; 24 | 25 | if (window.setImmediate) { 26 | exports.setImmediate = window.setImmediate; 27 | exports.clearImmediate = window.clearImmediate; 28 | } 29 | 30 | // Chrome and PhantomJS seems to depend on `this` pseudo variable being a 31 | // `window` and throws invalid invocation exception otherwise. If this code 32 | // runs in such JS runtime next line will throw and `catch` clause will 33 | // exported timers functions bound to a window. 34 | exports.setTimeout(function() {}); 35 | } catch (_) { 36 | function bind(f, context) { 37 | return function () { return f.apply(context, arguments) }; 38 | } 39 | 40 | if (typeof window !== 'undefined') { 41 | exports.setTimeout = bind(setTimeout, window); 42 | exports.setInterval = bind(setInterval, window); 43 | exports.clearTimeout = bind(clearTimeout, window); 44 | exports.clearInterval = bind(clearInterval, window); 45 | if (window.setImmediate) { 46 | exports.setImmediate = bind(window.setImmediate, window); 47 | exports.clearImmediate = bind(window.clearImmediate, window); 48 | } 49 | } else { 50 | if (typeof setTimeout !== 'undefined') { 51 | exports.setTimeout = setTimeout; 52 | } 53 | if (typeof setInterval !== 'undefined') { 54 | exports.setInterval = setInterval; 55 | } 56 | if (typeof clearTimeout !== 'undefined') { 57 | exports.clearTimeout = clearTimeout; 58 | } 59 | if (typeof clearInterval === 'function') { 60 | exports.clearInterval = clearInterval; 61 | } 62 | } 63 | } 64 | 65 | exports.unref = function unref() {}; 66 | exports.ref = function ref() {}; 67 | 68 | if (!exports.setImmediate) { 69 | var currentKey = 0, queue = {}, active = false; 70 | 71 | exports.setImmediate = (function () { 72 | function drain() { 73 | active = false; 74 | for (var key in queue) { 75 | if (queue.hasOwnProperty(currentKey, key)) { 76 | var fn = queue[key]; 77 | delete queue[key]; 78 | fn(); 79 | } 80 | } 81 | } 82 | 83 | if (typeof window !== 'undefined' && 84 | window.postMessage && window.addEventListener) { 85 | window.addEventListener('message', function (ev) { 86 | if (ev.source === window && ev.data === 'browserify-tick') { 87 | ev.stopPropagation(); 88 | drain(); 89 | } 90 | }, true); 91 | 92 | return function setImmediate(fn) { 93 | var id = ++currentKey; 94 | queue[id] = fn; 95 | if (!active) { 96 | active = true; 97 | window.postMessage('browserify-tick', '*'); 98 | } 99 | return id; 100 | }; 101 | } else { 102 | return function setImmediate(fn) { 103 | var id = ++currentKey; 104 | queue[id] = fn; 105 | if (!active) { 106 | active = true; 107 | setTimeout(drain, 0); 108 | } 109 | return id; 110 | }; 111 | } 112 | })(); 113 | 114 | exports.clearImmediate = function clearImmediate(id) { 115 | delete queue[id]; 116 | }; 117 | } 118 | -------------------------------------------------------------------------------- /test/browser/stream2-readable-empty-buffer-no-eof.js: -------------------------------------------------------------------------------- 1 | // Copyright Joyent, Inc. and other Node contributors. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the 5 | // "Software"), to deal in the Software without restriction, including 6 | // without limitation the rights to use, copy, modify, merge, publish, 7 | // distribute, sublicense, and/or sell copies of the Software, and to permit 8 | // persons to whom the Software is furnished to do so, subject to the 9 | // following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included 12 | // in all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 17 | // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 20 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | var test = require('tape'); 23 | var timers = require('timers'); 24 | var Buffer = require('buffer').Buffer; 25 | var Readable = require('stream').Readable; 26 | 27 | test('steam2 - readable empty buffer to eof - 1', function (t) { 28 | var r = new Readable(); 29 | 30 | // should not end when we get a Buffer(0) or '' as the _read result 31 | // that just means that there is *temporarily* no data, but to go 32 | // ahead and try again later. 33 | // 34 | // note that this is very unusual. it only works for crypto streams 35 | // because the other side of the stream will call read(0) to cycle 36 | // data through openssl. that's why we set the timeouts to call 37 | // r.read(0) again later, otherwise there is no more work being done 38 | // and the process just exits. 39 | 40 | var buf = new Buffer(5); 41 | buf.fill('x'); 42 | var reads = 5; 43 | r._read = function(n) { 44 | switch (reads--) { 45 | case 0: 46 | return r.push(null); // EOF 47 | case 1: 48 | return r.push(buf); 49 | case 2: 50 | setTimeout(r.read.bind(r, 0), 10); 51 | return r.push(new Buffer(0)); // Not-EOF! 52 | case 3: 53 | setTimeout(r.read.bind(r, 0), 10); 54 | return timers.setImmediate(function() { 55 | return r.push(new Buffer(0)); 56 | }); 57 | case 4: 58 | setTimeout(r.read.bind(r, 0), 10); 59 | return setTimeout(function() { 60 | return r.push(new Buffer(0)); 61 | }); 62 | case 5: 63 | return setTimeout(function() { 64 | return r.push(buf); 65 | }); 66 | default: 67 | throw new Error('unreachable'); 68 | } 69 | }; 70 | 71 | var results = []; 72 | function flow() { 73 | var chunk; 74 | while (null !== (chunk = r.read())) 75 | results.push(chunk + ''); 76 | } 77 | r.on('readable', flow); 78 | r.on('end', function() { 79 | results.push('EOF'); 80 | }); 81 | flow(); 82 | 83 | function done() { 84 | t.deepEqual(results, [ 'xxxxx', 'xxxxx', 'EOF' ]); 85 | t.end(); 86 | } 87 | r.on('end', done); 88 | }); 89 | 90 | test('steam2 - readable empty buffer to eof - 2', function (t) { 91 | var r = new Readable({ encoding: 'base64' }); 92 | var reads = 5; 93 | r._read = function(n) { 94 | if (!reads--) 95 | return r.push(null); // EOF 96 | else 97 | return r.push(new Buffer('x')); 98 | }; 99 | 100 | var results = []; 101 | function flow() { 102 | var chunk; 103 | while (null !== (chunk = r.read())) 104 | results.push(chunk + ''); 105 | } 106 | r.on('readable', flow); 107 | r.on('end', function() { 108 | results.push('EOF'); 109 | }); 110 | flow(); 111 | 112 | function done() { 113 | t.deepEqual(results, [ 'eHh4', 'eHg=', 'EOF' ]); 114 | t.end(); 115 | } 116 | r.on('end', done); 117 | }); 118 | -------------------------------------------------------------------------------- /test/browser/stream-readable-event.js: -------------------------------------------------------------------------------- 1 | // Copyright Joyent, Inc. and other Node contributors. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the 5 | // "Software"), to deal in the Software without restriction, including 6 | // without limitation the rights to use, copy, modify, merge, publish, 7 | // distribute, sublicense, and/or sell copies of the Software, and to permit 8 | // persons to whom the Software is furnished to do so, subject to the 9 | // following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included 12 | // in all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 17 | // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 20 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | var test = require('tape'); 23 | var timers = require('timers'); 24 | var Buffer = require('buffer').Buffer; 25 | 26 | var Readable = require('stream').Readable; 27 | 28 | test('stream.Readable - readable event - first', function (t) { 29 | // First test, not reading when the readable is added. 30 | // make sure that on('readable', ...) triggers a readable event. 31 | var r = new Readable({ 32 | highWaterMark: 3 33 | }); 34 | 35 | var _readCalled = false; 36 | r._read = function(n) { 37 | _readCalled = true; 38 | }; 39 | 40 | // This triggers a 'readable' event, which is lost. 41 | r.push(new Buffer('blerg')); 42 | 43 | var caughtReadable = false; 44 | timers.setImmediate(function() { 45 | // we're testing what we think we are 46 | t.ok(!r._readableState.reading); 47 | r.on('readable', function() { 48 | caughtReadable = true; 49 | done(); 50 | }); 51 | }); 52 | 53 | function done() { 54 | // we're testing what we think we are 55 | t.ok(!_readCalled); 56 | 57 | t.ok(caughtReadable); 58 | t.end(); 59 | } 60 | }); 61 | 62 | test('stream.Readable - readable event - second', function (t) { 63 | // second test, make sure that readable is re-emitted if there's 64 | // already a length, while it IS reading. 65 | 66 | var r = new Readable({ 67 | highWaterMark: 3 68 | }); 69 | 70 | var _readCalled = false; 71 | r._read = function(n) { 72 | _readCalled = true; 73 | if (_readCalled && caughtReadable) t.end(); 74 | }; 75 | 76 | // This triggers a 'readable' event, which is lost. 77 | r.push(new Buffer('bl')); 78 | 79 | var caughtReadable = false; 80 | timers.setImmediate(function() { 81 | // assert we're testing what we think we are 82 | t.ok(r._readableState.reading); 83 | r.on('readable', function() { 84 | caughtReadable = true; 85 | if (_readCalled && caughtReadable) t.end(); 86 | }); 87 | }); 88 | }); 89 | 90 | test('stream.Readable - readable event - third', function (t) { 91 | // Third test, not reading when the stream has not passed 92 | // the highWaterMark but *has* reached EOF. 93 | var r = new Readable({ 94 | highWaterMark: 30 95 | }); 96 | 97 | var _readCalled = false; 98 | r._read = function(n) { 99 | _readCalled = true; 100 | }; 101 | 102 | // This triggers a 'readable' event, which is lost. 103 | r.push(new Buffer('blerg')); 104 | r.push(null); 105 | 106 | var caughtReadable = false; 107 | timers.setImmediate(function() { 108 | // assert we're testing what we think we are 109 | t.ok(!r._readableState.reading); 110 | r.on('readable', function() { 111 | caughtReadable = true; 112 | done(); 113 | }); 114 | }); 115 | 116 | function done() { 117 | // we're testing what we think we are 118 | t.ok(!_readCalled); 119 | 120 | t.ok(caughtReadable); 121 | t.end(); 122 | } 123 | }); 124 | -------------------------------------------------------------------------------- /builtin/stream.js: -------------------------------------------------------------------------------- 1 | // Copyright Joyent, Inc. and other Node contributors. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the 5 | // "Software"), to deal in the Software without restriction, including 6 | // without limitation the rights to use, copy, modify, merge, publish, 7 | // distribute, sublicense, and/or sell copies of the Software, and to permit 8 | // persons to whom the Software is furnished to do so, subject to the 9 | // following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included 12 | // in all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 17 | // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 20 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | module.exports = Stream; 23 | 24 | var EE = require('events').EventEmitter; 25 | var util = require('util'); 26 | 27 | util.inherits(Stream, EE); 28 | Stream.Readable = require('_stream_readable'); 29 | Stream.Writable = require('_stream_writable'); 30 | Stream.Duplex = require('_stream_duplex'); 31 | Stream.Transform = require('_stream_transform'); 32 | Stream.PassThrough = require('_stream_passthrough'); 33 | 34 | // Backwards-compat with node 0.4.x 35 | Stream.Stream = Stream; 36 | 37 | 38 | 39 | // old-style streams. Note that the pipe method (the only relevant 40 | // part of this class) is overridden in the Readable class. 41 | 42 | function Stream() { 43 | EE.call(this); 44 | } 45 | 46 | Stream.prototype.pipe = function(dest, options) { 47 | var source = this; 48 | 49 | function ondata(chunk) { 50 | if (dest.writable) { 51 | if (false === dest.write(chunk) && source.pause) { 52 | source.pause(); 53 | } 54 | } 55 | } 56 | 57 | source.on('data', ondata); 58 | 59 | function ondrain() { 60 | if (source.readable && source.resume) { 61 | source.resume(); 62 | } 63 | } 64 | 65 | dest.on('drain', ondrain); 66 | 67 | // If the 'end' option is not supplied, dest.end() will be called when 68 | // source gets the 'end' or 'close' events. Only dest.end() once. 69 | if (!dest._isStdio && (!options || options.end !== false)) { 70 | source.on('end', onend); 71 | source.on('close', onclose); 72 | } 73 | 74 | var didOnEnd = false; 75 | function onend() { 76 | if (didOnEnd) return; 77 | didOnEnd = true; 78 | 79 | dest.end(); 80 | } 81 | 82 | 83 | function onclose() { 84 | if (didOnEnd) return; 85 | didOnEnd = true; 86 | 87 | if (typeof dest.destroy === 'function') dest.destroy(); 88 | } 89 | 90 | // don't leave dangling pipes when there are errors. 91 | function onerror(er) { 92 | cleanup(); 93 | if (EE.listenerCount(this, 'error') === 0) { 94 | throw er; // Unhandled stream error in pipe. 95 | } 96 | } 97 | 98 | source.on('error', onerror); 99 | dest.on('error', onerror); 100 | 101 | // remove all the event listeners that were added. 102 | function cleanup() { 103 | source.removeListener('data', ondata); 104 | dest.removeListener('drain', ondrain); 105 | 106 | source.removeListener('end', onend); 107 | source.removeListener('close', onclose); 108 | 109 | source.removeListener('error', onerror); 110 | dest.removeListener('error', onerror); 111 | 112 | source.removeListener('end', cleanup); 113 | source.removeListener('close', cleanup); 114 | 115 | dest.removeListener('close', cleanup); 116 | } 117 | 118 | source.on('end', cleanup); 119 | source.on('close', cleanup); 120 | 121 | dest.on('close', cleanup); 122 | 123 | dest.emit('pipe', source); 124 | 125 | // Allow for unix-like usage: A.pipe(B).pipe(C) 126 | return dest; 127 | }; 128 | -------------------------------------------------------------------------------- /test/browser/stream-pipe-cleanup.js: -------------------------------------------------------------------------------- 1 | // Copyright Joyent, Inc. and other Node contributors. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the 5 | // "Software"), to deal in the Software without restriction, including 6 | // without limitation the rights to use, copy, modify, merge, publish, 7 | // distribute, sublicense, and/or sell copies of the Software, and to permit 8 | // persons to whom the Software is furnished to do so, subject to the 9 | // following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included 12 | // in all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 17 | // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 20 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | var stream = require('stream'); 23 | 24 | var test = require('tape'); 25 | var util = require('util'); 26 | 27 | test('stream - pipe cleanup', function (t) { 28 | function Writable() { 29 | this.writable = true; 30 | this.endCalls = 0; 31 | stream.Stream.call(this); 32 | } 33 | util.inherits(Writable, stream.Stream); 34 | Writable.prototype.end = function() { 35 | this.endCalls++; 36 | }; 37 | 38 | Writable.prototype.destroy = function() { 39 | this.endCalls++; 40 | }; 41 | 42 | function Readable() { 43 | this.readable = true; 44 | stream.Stream.call(this); 45 | } 46 | util.inherits(Readable, stream.Stream); 47 | 48 | function Duplex() { 49 | this.readable = true; 50 | Writable.call(this); 51 | } 52 | util.inherits(Duplex, Writable); 53 | 54 | var i = 0; 55 | var limit = 100; 56 | 57 | var w = new Writable(); 58 | 59 | var r; 60 | 61 | for (i = 0; i < limit; i++) { 62 | r = new Readable(); 63 | r.pipe(w); 64 | r.emit('end'); 65 | } 66 | t.equal(0, r.listeners('end').length); 67 | t.equal(limit, w.endCalls); 68 | 69 | w.endCalls = 0; 70 | 71 | for (i = 0; i < limit; i++) { 72 | r = new Readable(); 73 | r.pipe(w); 74 | r.emit('close'); 75 | } 76 | t.equal(0, r.listeners('close').length); 77 | t.equal(limit, w.endCalls); 78 | 79 | w.endCalls = 0; 80 | 81 | r = new Readable(); 82 | 83 | for (i = 0; i < limit; i++) { 84 | w = new Writable(); 85 | r.pipe(w); 86 | w.emit('close'); 87 | } 88 | t.equal(0, w.listeners('close').length); 89 | 90 | r = new Readable(); 91 | w = new Writable(); 92 | var d = new Duplex(); 93 | r.pipe(d); // pipeline A 94 | d.pipe(w); // pipeline B 95 | t.equal(r.listeners('end').length, 2); // A.onend, A.cleanup 96 | t.equal(r.listeners('close').length, 2); // A.onclose, A.cleanup 97 | t.equal(d.listeners('end').length, 2); // B.onend, B.cleanup 98 | t.equal(d.listeners('close').length, 3); // A.cleanup, B.onclose, B.cleanup 99 | t.equal(w.listeners('end').length, 0); 100 | t.equal(w.listeners('close').length, 1); // B.cleanup 101 | 102 | r.emit('end'); 103 | t.equal(d.endCalls, 1); 104 | t.equal(w.endCalls, 0); 105 | t.equal(r.listeners('end').length, 0); 106 | t.equal(r.listeners('close').length, 0); 107 | t.equal(d.listeners('end').length, 2); // B.onend, B.cleanup 108 | t.equal(d.listeners('close').length, 2); // B.onclose, B.cleanup 109 | t.equal(w.listeners('end').length, 0); 110 | t.equal(w.listeners('close').length, 1); // B.cleanup 111 | 112 | d.emit('end'); 113 | t.equal(d.endCalls, 1); 114 | t.equal(w.endCalls, 1); 115 | t.equal(r.listeners('end').length, 0); 116 | t.equal(r.listeners('close').length, 0); 117 | t.equal(d.listeners('end').length, 0); 118 | t.equal(d.listeners('close').length, 0); 119 | t.equal(w.listeners('end').length, 0); 120 | t.equal(w.listeners('close').length, 0); 121 | 122 | t.end(); 123 | }); 124 | -------------------------------------------------------------------------------- /test/browser/stream-unshift-read-race.js: -------------------------------------------------------------------------------- 1 | // Copyright Joyent, Inc. and other Node contributors. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the 5 | // "Software"), to deal in the Software without restriction, including 6 | // without limitation the rights to use, copy, modify, merge, publish, 7 | // distribute, sublicense, and/or sell copies of the Software, and to permit 8 | // persons to whom the Software is furnished to do so, subject to the 9 | // following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included 12 | // in all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 17 | // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 20 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | var test = require('tape'); 23 | var Buffer = require('buffer').Buffer; 24 | 25 | // This test verifies that: 26 | // 1. unshift() does not cause colliding _read() calls. 27 | // 2. unshift() after the 'end' event is an error, but after the EOF 28 | // signalling null, it is ok, and just creates a new readable chunk. 29 | // 3. push() after the EOF signaling null is an error. 30 | // 4. _read() is not called after pushing the EOF null chunk. 31 | 32 | var stream = require('stream'); 33 | 34 | test('stream - unshift read race', function (tt) { 35 | var hwm = 10; 36 | var r = stream.Readable({ highWaterMark: hwm }); 37 | var chunks = 10; 38 | var t = (chunks * 5); 39 | 40 | var data = new Buffer(chunks * hwm + Math.ceil(hwm / 2)); 41 | for (var i = 0; i < data.length; i++) { 42 | var c = 'asdf'.charCodeAt(i % 4); 43 | data[i] = c; 44 | } 45 | 46 | var pos = 0; 47 | var pushedNull = false; 48 | r._read = function(n) { 49 | tt.ok(!pushedNull, '_read after null push'); 50 | 51 | // every third chunk is fast 52 | push(!(chunks % 3)); 53 | 54 | function push(fast) { 55 | tt.ok(!pushedNull, 'push() after null push'); 56 | var c = pos >= data.length ? null : data.slice(pos, pos + n); 57 | pushedNull = c === null; 58 | if (fast) { 59 | pos += n; 60 | r.push(c); 61 | if (c === null) pushError(); 62 | } else { 63 | setTimeout(function() { 64 | pos += n; 65 | r.push(c); 66 | if (c === null) pushError(); 67 | }); 68 | } 69 | } 70 | }; 71 | 72 | function pushError() { 73 | tt.throws(function() { 74 | r.push(new Buffer(1)); 75 | }); 76 | } 77 | 78 | 79 | var w = stream.Writable(); 80 | var written = []; 81 | w._write = function(chunk, encoding, cb) { 82 | written.push(chunk.toString()); 83 | cb(); 84 | }; 85 | 86 | var ended = false; 87 | r.on('end', function() { 88 | tt.ok(!ended, 'end emitted more than once'); 89 | tt.throws(function() { 90 | r.unshift(new Buffer(1)); 91 | }); 92 | ended = true; 93 | w.end(); 94 | }); 95 | 96 | r.on('readable', function() { 97 | var chunk; 98 | while (null !== (chunk = r.read(10))) { 99 | w.write(chunk); 100 | if (chunk.length > 4) 101 | r.unshift(new Buffer('1234')); 102 | } 103 | }); 104 | 105 | var finished = false; 106 | w.on('finish', function() { 107 | finished = true; 108 | // each chunk should start with 1234, and then be asfdasdfasdf... 109 | // The first got pulled out before the first unshift('1234'), so it's 110 | // lacking that piece. 111 | tt.equal(written[0], 'asdfasdfas'); 112 | var asdf = 'd'; 113 | for (var i = 1; i < written.length; i++) { 114 | tt.equal(written[i].slice(0, 4), '1234'); 115 | for (var j = 4; j < written[i].length; j++) { 116 | var c = written[i].charAt(j); 117 | tt.equal(c, asdf); 118 | switch (asdf) { 119 | case 'a': asdf = 's'; break; 120 | case 's': asdf = 'd'; break; 121 | case 'd': asdf = 'f'; break; 122 | case 'f': asdf = 'a'; break; 123 | } 124 | } 125 | } 126 | }); 127 | 128 | function done() { 129 | tt.equal(written.length, 18); 130 | tt.ok(ended, 'stream ended'); 131 | tt.ok(finished, 'stream finished'); 132 | tt.end(); 133 | } 134 | w.on('finish', done); 135 | }); 136 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Browser altenatives to built-in node.js modules 2 | 3 | This is used by `browserify` module. Initially these files were in `node-browser-resolve` 4 | but [disappeared in v1.0.1](https://github.com/shtylman/node-browser-resolve/commit/2799bcc316052a53fdafecd39576e14673a47ab0) 5 | which broke `browserify` dependency. This module is that missing dependency. 6 | 7 | [![Dependency status](https://david-dm.org/alexgorbatchev/node-browser-builtins.png)](https://david-dm.org/alexgorbatchev/node-browser-builtins) [![Build status](https://travis-ci.org/alexgorbatchev/node-browser-builtins.png)](https://travis-ci.org/alexgorbatchev/node-browser-builtins) 8 | 9 | ## Browser support 10 | 11 | * Safari: latest 12 | * Chrome: latest 13 | * Firefox: latest 14 | * Opera: latest 15 | * Internet Explore: 10, 11 16 | 17 | #### Legacy browsers 18 | 19 | This decision behind not supporting legacy browsers was made to reduce the 20 | maintenance and allow usage of more advanced browser features such as 21 | TypedArrays. Please do not supply pull requests there adds support for 22 | legacy browsers. Instead we recommend that you use the necessary polyfills 23 | for legacy browser support. Should you be willing to start your own complete 24 | browser-builtins polyfills project, then feel free to contact us for tips 25 | and hints. 26 | 27 | ## Documentation 28 | 29 | Requireing this module gives you a simple map between the modulename and a 30 | filepath to the module containing the shim. You can then point to these files 31 | in your pseudo-node implementation. Note that beyond the nodecore modules 32 | there is also a process module, there mimics `global.process` in node. 33 | 34 | ```javascript 35 | require('browser-builtins'); 36 | ``` 37 | 38 | ```javascript 39 | { 40 | assert: '/user/node_modules/browser-builtins/builtin/assert.js', 41 | child_process: '/user/node_modules/browser-builtins/builtin/child_process.js', 42 | cluster: '/user/node_modules/browser-builtins/builtin/cluster.js', 43 | dgram: '/user/node_modules/browser-builtins/builtin/dgram.js', 44 | dns: '/user/node_modules/browser-builtins/builtin/dns.js', 45 | domain: '/user/node_modules/browser-builtins/builtin/domain.js', 46 | events: '/user/node_modules/browser-builtins/builtin/events.js', 47 | fs: '/user/node_modules/browser-builtins/builtin/fs.js', 48 | https: '/user/node_modules/browser-builtins/builtin/https.js', 49 | net: '/user/node_modules/browser-builtins/builtin/net.js', 50 | path: '/user/node_modules/browser-builtins/builtin/path.js', 51 | process: '/user/node_modules/browser-builtins/builtin/process.js', 52 | querystring: '/user/node_modules/browser-builtins/builtin/querystring.js', 53 | readline: '/user/node_modules/browser-builtins/builtin/readline.js', 54 | repl: '/user/node_modules/browser-builtins/builtin/repl.js', 55 | stream: '/user/node_modules/browser-builtins/builtin/stream.js', 56 | string_decoder: '/user/node_modules/browser-builtins/builtin/string_decoder.js', 57 | sys: '/user/node_modules/browser-builtins/builtin/sys.js', 58 | timers: '/user/node_modules/browser-builtins/builtin/timers.js', 59 | tls: '/user/node_modules/browser-builtins/builtin/tls.js', 60 | tty: '/user/node_modules/browser-builtins/builtin/tty.js', 61 | url: '/user/node_modules/browser-builtins/builtin/url.js', 62 | util: '/user/node_modules/browser-builtins/builtin/util.js', 63 | punycode: '/user/node_modules/browser-builtins/node_modules/punycode/punycode.js', 64 | http: '/user/node_modules/browser-builtins/node_modules/http-browserify/index.js', 65 | vm: '/user/node_modules/browser-builtins/node_modules/vm-browserify/index.js', 66 | crypto: '/user/node_modules/browser-builtins/node_modules/crypto-browserify/index.js', 67 | console: '/user/node_modules/browser-builtins/node_modules/console-browserify/index.js', 68 | zlib: '/user/node_modules/browser-builtins/node_modules/zlib-browserify/index.js', 69 | buffer: '/user/node_modules/browser-builtins/node_modules/buffer/index.js', 70 | constants: '/user/node_modules/browser-builtins/node_modules/constants-browserify/constants.json', 71 | os: '/user/node_modules/browser-builtins/node_modules/os-browserify/browser.js' 72 | } 73 | ``` 74 | 75 | ## Contribute 76 | 77 | When fixing a bug please check the following: 78 | 79 | 1. Check that the bug do not exist in node and fix it there first 80 | 2. Check that updating the code from the node source dosn't fix it 81 | 3. It must be a browser issue, fix it here. But do please link to the browser bug report 82 | 83 | ## Testing 84 | 85 | `node-browser-builtins` uses [zuul](https://github.com/defunctzombie/zuul) for client side testing. In summary, all you will need is a [Saucelabs](https://saucelabs.com) account (free one will work just fine). To get up and running with it, please follow [zuul instructions](https://github.com/defunctzombie/zuul/wiki/Cloud-testing). 86 | 87 | Finally, just run: 88 | 89 | npm test 90 | 91 | ## History 92 | 93 | 1. "Forked" from `node-browser-resolve`, originally written by Roman Shtylman (@shtylman). 94 | 2. Major update to node v0.10 and tests (@AndreasMadsen) 95 | 3. no legacy browser support (IE10+) 96 | -------------------------------------------------------------------------------- /builtin/querystring.js: -------------------------------------------------------------------------------- 1 | // Copyright Joyent, Inc. and other Node contributors. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the 5 | // "Software"), to deal in the Software without restriction, including 6 | // without limitation the rights to use, copy, modify, merge, publish, 7 | // distribute, sublicense, and/or sell copies of the Software, and to permit 8 | // persons to whom the Software is furnished to do so, subject to the 9 | // following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included 12 | // in all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 17 | // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 20 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | // Query String Utilities 23 | 24 | var QueryString = exports; 25 | var util = require('util'); 26 | var Buffer = require('buffer').Buffer; 27 | 28 | // If obj.hasOwnProperty has been overridden, then calling 29 | // obj.hasOwnProperty(prop) will break. 30 | // See: https://github.com/joyent/node/issues/1707 31 | function hasOwnProperty(obj, prop) { 32 | return Object.prototype.hasOwnProperty.call(obj, prop); 33 | } 34 | 35 | 36 | function charCode(c) { 37 | return c.charCodeAt(0); 38 | } 39 | 40 | 41 | // a safe fast alternative to decodeURIComponent 42 | QueryString.unescapeBuffer = function(s, decodeSpaces) { 43 | var out = new Buffer(s.length); 44 | var state = 'CHAR'; // states: CHAR, HEX0, HEX1 45 | var n, m, hexchar; 46 | 47 | for (var inIndex = 0, outIndex = 0; inIndex <= s.length; inIndex++) { 48 | var c = s.charCodeAt(inIndex); 49 | switch (state) { 50 | case 'CHAR': 51 | switch (c) { 52 | case charCode('%'): 53 | n = 0; 54 | m = 0; 55 | state = 'HEX0'; 56 | break; 57 | case charCode('+'): 58 | if (decodeSpaces) c = charCode(' '); 59 | // pass thru 60 | default: 61 | out[outIndex++] = c; 62 | break; 63 | } 64 | break; 65 | 66 | case 'HEX0': 67 | state = 'HEX1'; 68 | hexchar = c; 69 | if (charCode('0') <= c && c <= charCode('9')) { 70 | n = c - charCode('0'); 71 | } else if (charCode('a') <= c && c <= charCode('f')) { 72 | n = c - charCode('a') + 10; 73 | } else if (charCode('A') <= c && c <= charCode('F')) { 74 | n = c - charCode('A') + 10; 75 | } else { 76 | out[outIndex++] = charCode('%'); 77 | out[outIndex++] = c; 78 | state = 'CHAR'; 79 | break; 80 | } 81 | break; 82 | 83 | case 'HEX1': 84 | state = 'CHAR'; 85 | if (charCode('0') <= c && c <= charCode('9')) { 86 | m = c - charCode('0'); 87 | } else if (charCode('a') <= c && c <= charCode('f')) { 88 | m = c - charCode('a') + 10; 89 | } else if (charCode('A') <= c && c <= charCode('F')) { 90 | m = c - charCode('A') + 10; 91 | } else { 92 | out[outIndex++] = charCode('%'); 93 | out[outIndex++] = hexchar; 94 | out[outIndex++] = c; 95 | break; 96 | } 97 | out[outIndex++] = 16 * n + m; 98 | break; 99 | } 100 | } 101 | 102 | // TODO support returning arbitrary buffers. 103 | 104 | return out.slice(0, outIndex - 1); 105 | }; 106 | 107 | 108 | QueryString.unescape = function(s, decodeSpaces) { 109 | return QueryString.unescapeBuffer(s, decodeSpaces).toString(); 110 | }; 111 | 112 | 113 | QueryString.escape = function(str) { 114 | return encodeURIComponent(str); 115 | }; 116 | 117 | var stringifyPrimitive = function(v) { 118 | if (util.isString(v)) 119 | return v; 120 | if (util.isBoolean(v)) 121 | return v ? 'true' : 'false'; 122 | if (util.isNumber(v)) 123 | return isFinite(v) ? v : ''; 124 | return ''; 125 | }; 126 | 127 | 128 | QueryString.stringify = QueryString.encode = function(obj, sep, eq, name) { 129 | sep = sep || '&'; 130 | eq = eq || '='; 131 | if (util.isNull(obj)) { 132 | obj = undefined; 133 | } 134 | 135 | if (util.isObject(obj)) { 136 | return Object.keys(obj).map(function(k) { 137 | var ks = QueryString.escape(stringifyPrimitive(k)) + eq; 138 | if (util.isArray(obj[k])) { 139 | return obj[k].map(function(v) { 140 | return ks + QueryString.escape(stringifyPrimitive(v)); 141 | }).join(sep); 142 | } else { 143 | return ks + QueryString.escape(stringifyPrimitive(obj[k])); 144 | } 145 | }).join(sep); 146 | 147 | } 148 | 149 | if (!name) return ''; 150 | return QueryString.escape(stringifyPrimitive(name)) + eq + 151 | QueryString.escape(stringifyPrimitive(obj)); 152 | }; 153 | 154 | // Parse a key=val string. 155 | QueryString.parse = QueryString.decode = function(qs, sep, eq, options) { 156 | sep = sep || '&'; 157 | eq = eq || '='; 158 | var obj = {}; 159 | 160 | if (!util.isString(qs) || qs.length === 0) { 161 | return obj; 162 | } 163 | 164 | var regexp = /\+/g; 165 | qs = qs.split(sep); 166 | 167 | var maxKeys = 1000; 168 | if (options && util.isNumber(options.maxKeys)) { 169 | maxKeys = options.maxKeys; 170 | } 171 | 172 | var len = qs.length; 173 | // maxKeys <= 0 means that we should not limit keys count 174 | if (maxKeys > 0 && len > maxKeys) { 175 | len = maxKeys; 176 | } 177 | 178 | for (var i = 0; i < len; ++i) { 179 | var x = qs[i].replace(regexp, '%20'), 180 | idx = x.indexOf(eq), 181 | kstr, vstr, k, v; 182 | 183 | if (idx >= 0) { 184 | kstr = x.substr(0, idx); 185 | vstr = x.substr(idx + 1); 186 | } else { 187 | kstr = x; 188 | vstr = ''; 189 | } 190 | 191 | try { 192 | k = decodeURIComponent(kstr); 193 | v = decodeURIComponent(vstr); 194 | } catch (e) { 195 | k = QueryString.unescape(kstr, true); 196 | v = QueryString.unescape(vstr, true); 197 | } 198 | 199 | if (!hasOwnProperty(obj, k)) { 200 | obj[k] = v; 201 | } else if (util.isArray(obj[k])) { 202 | obj[k].push(v); 203 | } else { 204 | obj[k] = [obj[k], v]; 205 | } 206 | } 207 | 208 | return obj; 209 | }; -------------------------------------------------------------------------------- /test/browser/stream2-objects.js: -------------------------------------------------------------------------------- 1 | // Copyright Joyent, Inc. and other Node contributors. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the 5 | // "Software"), to deal in the Software without restriction, including 6 | // without limitation the rights to use, copy, modify, merge, publish, 7 | // distribute, sublicense, and/or sell copies of the Software, and to permit 8 | // persons to whom the Software is furnished to do so, subject to the 9 | // following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included 12 | // in all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 17 | // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 20 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | var Readable = require('stream').Readable; 23 | var Writable = require('stream').Writable; 24 | var test = require('tape'); 25 | var timers = require('timers'); 26 | 27 | function toArray(callback) { 28 | var stream = new Writable({ objectMode: true }); 29 | var list = []; 30 | stream.write = function(chunk) { 31 | list.push(chunk); 32 | }; 33 | 34 | stream.end = function() { 35 | callback(list); 36 | }; 37 | 38 | return stream; 39 | } 40 | 41 | function fromArray(list) { 42 | var r = new Readable({ objectMode: true }); 43 | r._read = noop; 44 | list.forEach(function(chunk) { 45 | r.push(chunk); 46 | }); 47 | r.push(null); 48 | 49 | return r; 50 | } 51 | 52 | function noop() {} 53 | 54 | test('can read objects from stream', function(t) { 55 | var r = fromArray([{ one: '1'}, { two: '2' }]); 56 | 57 | var v1 = r.read(); 58 | var v2 = r.read(); 59 | var v3 = r.read(); 60 | 61 | t.deepEqual(v1, { one: '1' }); 62 | t.deepEqual(v2, { two: '2' }); 63 | t.deepEqual(v3, null); 64 | 65 | t.end(); 66 | }); 67 | 68 | test('can pipe objects into stream', function(t) { 69 | var r = fromArray([{ one: '1'}, { two: '2' }]); 70 | 71 | r.pipe(toArray(function(list) { 72 | t.deepEqual(list, [ 73 | { one: '1' }, 74 | { two: '2' } 75 | ]); 76 | 77 | t.end(); 78 | })); 79 | }); 80 | 81 | test('read(n) is ignored', function(t) { 82 | var r = fromArray([{ one: '1'}, { two: '2' }]); 83 | 84 | var value = r.read(2); 85 | 86 | t.deepEqual(value, { one: '1' }); 87 | 88 | t.end(); 89 | }); 90 | 91 | test('can read objects from _read (sync)', function(t) { 92 | var r = new Readable({ objectMode: true }); 93 | var list = [{ one: '1'}, { two: '2' }]; 94 | r._read = function(n) { 95 | var item = list.shift(); 96 | r.push(item || null); 97 | }; 98 | 99 | r.pipe(toArray(function(list) { 100 | t.deepEqual(list, [ 101 | { one: '1' }, 102 | { two: '2' } 103 | ]); 104 | 105 | t.end(); 106 | })); 107 | }); 108 | 109 | test('can read objects from _read (async)', function(t) { 110 | var r = new Readable({ objectMode: true }); 111 | var list = [{ one: '1'}, { two: '2' }]; 112 | r._read = function(n) { 113 | var item = list.shift(); 114 | timers.setImmediate(function() { 115 | r.push(item || null); 116 | }); 117 | }; 118 | 119 | r.pipe(toArray(function(list) { 120 | t.deepEqual(list, [ 121 | { one: '1' }, 122 | { two: '2' } 123 | ]); 124 | 125 | t.end(); 126 | })); 127 | }); 128 | 129 | test('can read strings as objects', function(t) { 130 | var r = new Readable({ 131 | objectMode: true 132 | }); 133 | r._read = noop; 134 | var list = ['one', 'two', 'three']; 135 | list.forEach(function(str) { 136 | r.push(str); 137 | }); 138 | r.push(null); 139 | 140 | r.pipe(toArray(function(array) { 141 | t.deepEqual(array, list); 142 | 143 | t.end(); 144 | })); 145 | }); 146 | 147 | test('read(0) for object streams', function(t) { 148 | var r = new Readable({ 149 | objectMode: true 150 | }); 151 | r._read = noop; 152 | 153 | r.push('foobar'); 154 | r.push(null); 155 | 156 | var v = r.read(0); 157 | 158 | r.pipe(toArray(function(array) { 159 | t.deepEqual(array, ['foobar']); 160 | 161 | t.end(); 162 | })); 163 | }); 164 | 165 | test('falsey values', function(t) { 166 | var r = new Readable({ 167 | objectMode: true 168 | }); 169 | r._read = noop; 170 | 171 | r.push(false); 172 | r.push(0); 173 | r.push(''); 174 | r.push(null); 175 | 176 | r.pipe(toArray(function(array) { 177 | t.deepEqual(array, [false, 0, '']); 178 | 179 | t.end(); 180 | })); 181 | }); 182 | 183 | test('high watermark _read', function(t) { 184 | var r = new Readable({ 185 | highWaterMark: 6, 186 | objectMode: true 187 | }); 188 | var calls = 0; 189 | var list = ['1', '2', '3', '4', '5', '6', '7', '8']; 190 | 191 | r._read = function(n) { 192 | calls++; 193 | }; 194 | 195 | list.forEach(function(c) { 196 | r.push(c); 197 | }); 198 | 199 | var v = r.read(); 200 | 201 | t.equal(calls, 0); 202 | t.equal(v, '1'); 203 | 204 | var v2 = r.read(); 205 | 206 | t.equal(calls, 1); 207 | t.equal(v2, '2'); 208 | 209 | t.end(); 210 | }); 211 | 212 | test('high watermark push', function(t) { 213 | var r = new Readable({ 214 | highWaterMark: 6, 215 | objectMode: true 216 | }); 217 | r._read = function(n) {}; 218 | for (var i = 0; i < 6; i++) { 219 | var bool = r.push(i); 220 | t.equal(bool, i === 5 ? false : true); 221 | } 222 | 223 | t.end(); 224 | }); 225 | 226 | test('can write objects to stream', function(t) { 227 | var w = new Writable({ objectMode: true }); 228 | 229 | w._write = function(chunk, encoding, cb) { 230 | t.deepEqual(chunk, { foo: 'bar' }); 231 | cb(); 232 | }; 233 | 234 | w.on('finish', function() { 235 | t.end(); 236 | }); 237 | 238 | w.write({ foo: 'bar' }); 239 | w.end(); 240 | }); 241 | 242 | test('can write multiple objects to stream', function(t) { 243 | var w = new Writable({ objectMode: true }); 244 | var list = []; 245 | 246 | w._write = function(chunk, encoding, cb) { 247 | list.push(chunk); 248 | cb(); 249 | }; 250 | 251 | w.on('finish', function() { 252 | t.deepEqual(list, [0, 1, 2, 3, 4]); 253 | 254 | t.end(); 255 | }); 256 | 257 | w.write(0); 258 | w.write(1); 259 | w.write(2); 260 | w.write(3); 261 | w.write(4); 262 | w.end(); 263 | }); 264 | 265 | test('can write strings as objects', function(t) { 266 | var w = new Writable({ 267 | objectMode: true 268 | }); 269 | var list = []; 270 | 271 | w._write = function(chunk, encoding, cb) { 272 | list.push(chunk); 273 | timers.setImmediate(cb); 274 | }; 275 | 276 | w.on('finish', function() { 277 | t.deepEqual(list, ['0', '1', '2', '3', '4']); 278 | 279 | t.end(); 280 | }); 281 | 282 | w.write('0'); 283 | w.write('1'); 284 | w.write('2'); 285 | w.write('3'); 286 | w.write('4'); 287 | w.end(); 288 | }); 289 | 290 | test('buffers finish until cb is called', function(t) { 291 | var w = new Writable({ 292 | objectMode: true 293 | }); 294 | var called = false; 295 | 296 | w._write = function(chunk, encoding, cb) { 297 | t.equal(chunk, 'foo'); 298 | 299 | timers.setImmediate(function() { 300 | called = true; 301 | cb(); 302 | }); 303 | }; 304 | 305 | w.on('finish', function() { 306 | t.equal(called, true); 307 | 308 | t.end(); 309 | }); 310 | 311 | w.write('foo'); 312 | w.end(); 313 | }); 314 | -------------------------------------------------------------------------------- /builtin/_stream_transform.js: -------------------------------------------------------------------------------- 1 | // Copyright Joyent, Inc. and other Node contributors. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the 5 | // "Software"), to deal in the Software without restriction, including 6 | // without limitation the rights to use, copy, modify, merge, publish, 7 | // distribute, sublicense, and/or sell copies of the Software, and to permit 8 | // persons to whom the Software is furnished to do so, subject to the 9 | // following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included 12 | // in all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 17 | // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 20 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | // a transform stream is a readable/writable stream where you do 23 | // something with the data. Sometimes it's called a "filter", 24 | // but that's not a great name for it, since that implies a thing where 25 | // some bits pass through, and others are simply ignored. (That would 26 | // be a valid example of a transform, of course.) 27 | // 28 | // While the output is causally related to the input, it's not a 29 | // necessarily symmetric or synchronous transformation. For example, 30 | // a zlib stream might take multiple plain-text writes(), and then 31 | // emit a single compressed chunk some time in the future. 32 | // 33 | // Here's how this works: 34 | // 35 | // The Transform stream has all the aspects of the readable and writable 36 | // stream classes. When you write(chunk), that calls _write(chunk,cb) 37 | // internally, and returns false if there's a lot of pending writes 38 | // buffered up. When you call read(), that calls _read(n) until 39 | // there's enough pending readable data buffered up. 40 | // 41 | // In a transform stream, the written data is placed in a buffer. When 42 | // _read(n) is called, it transforms the queued up data, calling the 43 | // buffered _write cb's as it consumes chunks. If consuming a single 44 | // written chunk would result in multiple output chunks, then the first 45 | // outputted bit calls the readcb, and subsequent chunks just go into 46 | // the read buffer, and will cause it to emit 'readable' if necessary. 47 | // 48 | // This way, back-pressure is actually determined by the reading side, 49 | // since _read has to be called to start processing a new chunk. However, 50 | // a pathological inflate type of transform can cause excessive buffering 51 | // here. For example, imagine a stream where every byte of input is 52 | // interpreted as an integer from 0-255, and then results in that many 53 | // bytes of output. Writing the 4 bytes {ff,ff,ff,ff} would result in 54 | // 1kb of data being output. In this case, you could write a very small 55 | // amount of input, and end up with a very large amount of output. In 56 | // such a pathological inflating mechanism, there'd be no way to tell 57 | // the system to stop doing the transform. A single 4MB write could 58 | // cause the system to run out of memory. 59 | // 60 | // However, even in such a pathological case, only a single written chunk 61 | // would be consumed, and then the rest would wait (un-transformed) until 62 | // the results of the previous transformed chunk were consumed. 63 | 64 | module.exports = Transform; 65 | 66 | var Duplex = require('_stream_duplex'); 67 | var util = require('util'); 68 | util.inherits(Transform, Duplex); 69 | 70 | 71 | function TransformState(options, stream) { 72 | this.afterTransform = function(er, data) { 73 | return afterTransform(stream, er, data); 74 | }; 75 | 76 | this.needTransform = false; 77 | this.transforming = false; 78 | this.writecb = null; 79 | this.writechunk = null; 80 | } 81 | 82 | function afterTransform(stream, er, data) { 83 | var ts = stream._transformState; 84 | ts.transforming = false; 85 | 86 | var cb = ts.writecb; 87 | 88 | if (!cb) 89 | return stream.emit('error', new Error('no writecb in Transform class')); 90 | 91 | ts.writechunk = null; 92 | ts.writecb = null; 93 | 94 | if (data !== null && data !== undefined) 95 | stream.push(data); 96 | 97 | if (cb) 98 | cb(er); 99 | 100 | var rs = stream._readableState; 101 | rs.reading = false; 102 | if (rs.needReadable || rs.length < rs.highWaterMark) { 103 | stream._read(rs.highWaterMark); 104 | } 105 | } 106 | 107 | 108 | function Transform(options) { 109 | if (!(this instanceof Transform)) 110 | return new Transform(options); 111 | 112 | Duplex.call(this, options); 113 | 114 | var ts = this._transformState = new TransformState(options, this); 115 | 116 | // when the writable side finishes, then flush out anything remaining. 117 | var stream = this; 118 | 119 | // start out asking for a readable event once data is transformed. 120 | this._readableState.needReadable = true; 121 | 122 | // we have implemented the _read method, and done the other things 123 | // that Readable wants before the first _read call, so unset the 124 | // sync guard flag. 125 | this._readableState.sync = false; 126 | 127 | this.once('finish', function() { 128 | if ('function' === typeof this._flush) 129 | this._flush(function(er) { 130 | done(stream, er); 131 | }); 132 | else 133 | done(stream); 134 | }); 135 | } 136 | 137 | Transform.prototype.push = function(chunk, encoding) { 138 | this._transformState.needTransform = false; 139 | return Duplex.prototype.push.call(this, chunk, encoding); 140 | }; 141 | 142 | // This is the part where you do stuff! 143 | // override this function in implementation classes. 144 | // 'chunk' is an input chunk. 145 | // 146 | // Call `push(newChunk)` to pass along transformed output 147 | // to the readable side. You may call 'push' zero or more times. 148 | // 149 | // Call `cb(err)` when you are done with this chunk. If you pass 150 | // an error, then that'll put the hurt on the whole operation. If you 151 | // never call cb(), then you'll never get another chunk. 152 | Transform.prototype._transform = function(chunk, encoding, cb) { 153 | throw new Error('not implemented'); 154 | }; 155 | 156 | Transform.prototype._write = function(chunk, encoding, cb) { 157 | var ts = this._transformState; 158 | ts.writecb = cb; 159 | ts.writechunk = chunk; 160 | ts.writeencoding = encoding; 161 | if (!ts.transforming) { 162 | var rs = this._readableState; 163 | if (ts.needTransform || 164 | rs.needReadable || 165 | rs.length < rs.highWaterMark) 166 | this._read(rs.highWaterMark); 167 | } 168 | }; 169 | 170 | // Doesn't matter what the args are here. 171 | // _transform does all the work. 172 | // That we got here means that the readable side wants more data. 173 | Transform.prototype._read = function(n) { 174 | var ts = this._transformState; 175 | 176 | if (ts.writechunk && ts.writecb && !ts.transforming) { 177 | ts.transforming = true; 178 | this._transform(ts.writechunk, ts.writeencoding, ts.afterTransform); 179 | } else { 180 | // mark that we need a transform, so that any data that comes in 181 | // will get processed, now that we've asked for it. 182 | ts.needTransform = true; 183 | } 184 | }; 185 | 186 | 187 | function done(stream, er) { 188 | if (er) 189 | return stream.emit('error', er); 190 | 191 | // if there's nothing in the write buffer, then that means 192 | // that nothing more will ever be provided 193 | var ws = stream._writableState; 194 | var rs = stream._readableState; 195 | var ts = stream._transformState; 196 | 197 | if (ws.length) 198 | throw new Error('calling transform done when ws.length != 0'); 199 | 200 | if (ts.transforming) 201 | throw new Error('calling transform done when still transforming'); 202 | 203 | return stream.push(null); 204 | } 205 | -------------------------------------------------------------------------------- /test/browser/stream2-set-encoding.js: -------------------------------------------------------------------------------- 1 | // Copyright Joyent, Inc. and other Node contributors. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the 5 | // "Software"), to deal in the Software without restriction, including 6 | // without limitation the rights to use, copy, modify, merge, publish, 7 | // distribute, sublicense, and/or sell copies of the Software, and to permit 8 | // persons to whom the Software is furnished to do so, subject to the 9 | // following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included 12 | // in all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 17 | // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 20 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | var test = require('tape'); 23 | var Buffer = require('buffer').Buffer; 24 | var R = require('stream').Readable; 25 | var util = require('util'); 26 | 27 | util.inherits(TestReader, R); 28 | 29 | function TestReader(n, opts) { 30 | R.call(this, opts); 31 | 32 | this.pos = 0; 33 | this.len = n || 100; 34 | } 35 | 36 | TestReader.prototype._read = function(n) { 37 | setTimeout((function() { 38 | 39 | if (this.pos >= this.len) { 40 | // double push(null) to test eos handling 41 | this.push(null); 42 | return this.push(null); 43 | } 44 | 45 | n = Math.min(n, this.len - this.pos); 46 | if (n <= 0) { 47 | // double push(null) to test eos handling 48 | this.push(null); 49 | return this.push(null); 50 | } 51 | 52 | this.pos += n; 53 | var ret = new Buffer(n); 54 | ret.fill('a'); 55 | 56 | return this.push(ret); 57 | }).bind(this), 1); 58 | }; 59 | 60 | test('setEncoding utf8', function(t) { 61 | var tr = new TestReader(100); 62 | tr.setEncoding('utf8'); 63 | var out = []; 64 | var expect = 65 | [ 'aaaaaaaaaa', 66 | 'aaaaaaaaaa', 67 | 'aaaaaaaaaa', 68 | 'aaaaaaaaaa', 69 | 'aaaaaaaaaa', 70 | 'aaaaaaaaaa', 71 | 'aaaaaaaaaa', 72 | 'aaaaaaaaaa', 73 | 'aaaaaaaaaa', 74 | 'aaaaaaaaaa' ]; 75 | 76 | tr.on('readable', function flow() { 77 | var chunk; 78 | while (null !== (chunk = tr.read(10))) 79 | out.push(chunk); 80 | }); 81 | 82 | tr.on('end', function() { 83 | t.same(out, expect); 84 | t.end(); 85 | }); 86 | }); 87 | 88 | 89 | test('setEncoding hex', function(t) { 90 | var tr = new TestReader(100); 91 | tr.setEncoding('hex'); 92 | var out = []; 93 | var expect = 94 | [ '6161616161', 95 | '6161616161', 96 | '6161616161', 97 | '6161616161', 98 | '6161616161', 99 | '6161616161', 100 | '6161616161', 101 | '6161616161', 102 | '6161616161', 103 | '6161616161', 104 | '6161616161', 105 | '6161616161', 106 | '6161616161', 107 | '6161616161', 108 | '6161616161', 109 | '6161616161', 110 | '6161616161', 111 | '6161616161', 112 | '6161616161', 113 | '6161616161' ]; 114 | 115 | tr.on('readable', function flow() { 116 | var chunk; 117 | while (null !== (chunk = tr.read(10))) 118 | out.push(chunk); 119 | }); 120 | 121 | tr.on('end', function() { 122 | t.same(out, expect); 123 | t.end(); 124 | }); 125 | }); 126 | 127 | test('setEncoding hex with read(13)', function(t) { 128 | var tr = new TestReader(100); 129 | tr.setEncoding('hex'); 130 | var out = []; 131 | var expect = 132 | [ "6161616161616", 133 | "1616161616161", 134 | "6161616161616", 135 | "1616161616161", 136 | "6161616161616", 137 | "1616161616161", 138 | "6161616161616", 139 | "1616161616161", 140 | "6161616161616", 141 | "1616161616161", 142 | "6161616161616", 143 | "1616161616161", 144 | "6161616161616", 145 | "1616161616161", 146 | "6161616161616", 147 | "16161" ]; 148 | 149 | tr.on('readable', function flow() { 150 | var chunk; 151 | while (null !== (chunk = tr.read(13))) 152 | out.push(chunk); 153 | }); 154 | 155 | tr.on('end', function() { 156 | t.same(out, expect); 157 | t.end(); 158 | }); 159 | }); 160 | 161 | test('setEncoding base64', function(t) { 162 | var tr = new TestReader(100); 163 | tr.setEncoding('base64'); 164 | var out = []; 165 | var expect = 166 | [ 'YWFhYWFhYW', 167 | 'FhYWFhYWFh', 168 | 'YWFhYWFhYW', 169 | 'FhYWFhYWFh', 170 | 'YWFhYWFhYW', 171 | 'FhYWFhYWFh', 172 | 'YWFhYWFhYW', 173 | 'FhYWFhYWFh', 174 | 'YWFhYWFhYW', 175 | 'FhYWFhYWFh', 176 | 'YWFhYWFhYW', 177 | 'FhYWFhYWFh', 178 | 'YWFhYWFhYW', 179 | 'FhYQ==' ]; 180 | 181 | tr.on('readable', function flow() { 182 | var chunk; 183 | while (null !== (chunk = tr.read(10))) 184 | out.push(chunk); 185 | }); 186 | 187 | tr.on('end', function() { 188 | t.same(out, expect); 189 | t.end(); 190 | }); 191 | }); 192 | 193 | test('encoding: utf8', function(t) { 194 | var tr = new TestReader(100, { encoding: 'utf8' }); 195 | var out = []; 196 | var expect = 197 | [ 'aaaaaaaaaa', 198 | 'aaaaaaaaaa', 199 | 'aaaaaaaaaa', 200 | 'aaaaaaaaaa', 201 | 'aaaaaaaaaa', 202 | 'aaaaaaaaaa', 203 | 'aaaaaaaaaa', 204 | 'aaaaaaaaaa', 205 | 'aaaaaaaaaa', 206 | 'aaaaaaaaaa' ]; 207 | 208 | tr.on('readable', function flow() { 209 | var chunk; 210 | while (null !== (chunk = tr.read(10))) 211 | out.push(chunk); 212 | }); 213 | 214 | tr.on('end', function() { 215 | t.same(out, expect); 216 | t.end(); 217 | }); 218 | }); 219 | 220 | 221 | test('encoding: hex', function(t) { 222 | var tr = new TestReader(100, { encoding: 'hex' }); 223 | var out = []; 224 | var expect = 225 | [ '6161616161', 226 | '6161616161', 227 | '6161616161', 228 | '6161616161', 229 | '6161616161', 230 | '6161616161', 231 | '6161616161', 232 | '6161616161', 233 | '6161616161', 234 | '6161616161', 235 | '6161616161', 236 | '6161616161', 237 | '6161616161', 238 | '6161616161', 239 | '6161616161', 240 | '6161616161', 241 | '6161616161', 242 | '6161616161', 243 | '6161616161', 244 | '6161616161' ]; 245 | 246 | tr.on('readable', function flow() { 247 | var chunk; 248 | while (null !== (chunk = tr.read(10))) 249 | out.push(chunk); 250 | }); 251 | 252 | tr.on('end', function() { 253 | t.same(out, expect); 254 | t.end(); 255 | }); 256 | }); 257 | 258 | test('encoding: hex with read(13)', function(t) { 259 | var tr = new TestReader(100, { encoding: 'hex' }); 260 | var out = []; 261 | var expect = 262 | [ "6161616161616", 263 | "1616161616161", 264 | "6161616161616", 265 | "1616161616161", 266 | "6161616161616", 267 | "1616161616161", 268 | "6161616161616", 269 | "1616161616161", 270 | "6161616161616", 271 | "1616161616161", 272 | "6161616161616", 273 | "1616161616161", 274 | "6161616161616", 275 | "1616161616161", 276 | "6161616161616", 277 | "16161" ]; 278 | 279 | tr.on('readable', function flow() { 280 | var chunk; 281 | while (null !== (chunk = tr.read(13))) 282 | out.push(chunk); 283 | }); 284 | 285 | tr.on('end', function() { 286 | t.same(out, expect); 287 | t.end(); 288 | }); 289 | }); 290 | 291 | test('encoding: base64', function(t) { 292 | var tr = new TestReader(100, { encoding: 'base64' }); 293 | var out = []; 294 | var expect = 295 | [ 'YWFhYWFhYW', 296 | 'FhYWFhYWFh', 297 | 'YWFhYWFhYW', 298 | 'FhYWFhYWFh', 299 | 'YWFhYWFhYW', 300 | 'FhYWFhYWFh', 301 | 'YWFhYWFhYW', 302 | 'FhYWFhYWFh', 303 | 'YWFhYWFhYW', 304 | 'FhYWFhYWFh', 305 | 'YWFhYWFhYW', 306 | 'FhYWFhYWFh', 307 | 'YWFhYWFhYW', 308 | 'FhYQ==' ]; 309 | 310 | tr.on('readable', function flow() { 311 | var chunk; 312 | while (null !== (chunk = tr.read(10))) 313 | out.push(chunk); 314 | }); 315 | 316 | tr.on('end', function() { 317 | t.same(out, expect); 318 | t.end(); 319 | }); 320 | }); 321 | -------------------------------------------------------------------------------- /test/browser/querystring-simple.js: -------------------------------------------------------------------------------- 1 | // Copyright Joyent, Inc. and other Node contributors. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the 5 | // "Software"), to deal in the Software without restriction, including 6 | // without limitation the rights to use, copy, modify, merge, publish, 7 | // distribute, sublicense, and/or sell copies of the Software, and to permit 8 | // persons to whom the Software is furnished to do so, subject to the 9 | // following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included 12 | // in all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 17 | // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 20 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | var test = require('tape'); 23 | 24 | var qs = require('querystring'); 25 | 26 | // folding block, commented to pass gjslint 27 | // {{{ 28 | // [ wonkyQS, canonicalQS, obj ] 29 | var qsTestCases = [ 30 | ['foo=918854443121279438895193', 31 | 'foo=918854443121279438895193', 32 | {'foo': '918854443121279438895193'}], 33 | ['foo=bar', 'foo=bar', {'foo': 'bar'}], 34 | ['foo=bar&foo=quux', 'foo=bar&foo=quux', {'foo': ['bar', 'quux']}], 35 | ['foo=1&bar=2', 'foo=1&bar=2', {'foo': '1', 'bar': '2'}], 36 | ['my+weird+field=q1%212%22%27w%245%267%2Fz8%29%3F', 37 | 'my%20weird%20field=q1!2%22\'w%245%267%2Fz8)%3F', 38 | {'my weird field': 'q1!2"\'w$5&7/z8)?' }], 39 | ['foo%3Dbaz=bar', 'foo%3Dbaz=bar', {'foo=baz': 'bar'}], 40 | ['foo=baz=bar', 'foo=baz%3Dbar', {'foo': 'baz=bar'}], 41 | ['str=foo&arr=1&arr=2&arr=3&somenull=&undef=', 42 | 'str=foo&arr=1&arr=2&arr=3&somenull=&undef=', 43 | { 'str': 'foo', 44 | 'arr': ['1', '2', '3'], 45 | 'somenull': '', 46 | 'undef': ''}], 47 | [' foo = bar ', '%20foo%20=%20bar%20', {' foo ': ' bar '}], 48 | ['foo=%zx', 'foo=%25zx', {'foo': '%zx'}], 49 | ['foo=%EF%BF%BD', 'foo=%EF%BF%BD', {'foo': '\ufffd' }], 50 | // See: https://github.com/joyent/node/issues/1707 51 | ['hasOwnProperty=x&toString=foo&valueOf=bar&__defineGetter__=baz', 52 | 'hasOwnProperty=x&toString=foo&valueOf=bar&__defineGetter__=baz', 53 | { hasOwnProperty: 'x', 54 | toString: 'foo', 55 | valueOf: 'bar', 56 | __defineGetter__: 'baz' }], 57 | // See: https://github.com/joyent/node/issues/3058 58 | ['foo&bar=baz', 'foo=&bar=baz', { foo: '', bar: 'baz' }] 59 | ]; 60 | 61 | // [ wonkyQS, canonicalQS, obj ] 62 | var qsColonTestCases = [ 63 | ['foo:bar', 'foo:bar', {'foo': 'bar'}], 64 | ['foo:bar;foo:quux', 'foo:bar;foo:quux', {'foo': ['bar', 'quux']}], 65 | ['foo:1&bar:2;baz:quux', 66 | 'foo:1%26bar%3A2;baz:quux', 67 | {'foo': '1&bar:2', 'baz': 'quux'}], 68 | ['foo%3Abaz:bar', 'foo%3Abaz:bar', {'foo:baz': 'bar'}], 69 | ['foo:baz:bar', 'foo:baz%3Abar', {'foo': 'baz:bar'}] 70 | ]; 71 | 72 | // [wonkyObj, qs, canonicalObj] 73 | var extendedFunction = function() {}; 74 | extendedFunction.prototype = {a: 'b'}; 75 | var qsWeirdObjects = [ 76 | [{regexp: /./g}, 'regexp=', {'regexp': ''}], 77 | [{regexp: new RegExp('.', 'g')}, 'regexp=', {'regexp': ''}], 78 | [{fn: function() {}}, 'fn=', {'fn': ''}], 79 | [{fn: new Function('')}, 'fn=', {'fn': ''}], 80 | [{math: Math}, 'math=', {'math': ''}], 81 | [{e: extendedFunction}, 'e=', {'e': ''}], 82 | [{d: new Date()}, 'd=', {'d': ''}], 83 | [{d: Date}, 'd=', {'d': ''}], 84 | [{f: new Boolean(false), t: new Boolean(true)}, 'f=&t=', {'f': '', 't': ''}], 85 | [{f: false, t: true}, 'f=false&t=true', {'f': 'false', 't': 'true'}], 86 | [{n: null}, 'n=', {'n': ''}], 87 | [{nan: NaN}, 'nan=', {'nan': ''}], 88 | [{inf: Infinity}, 'inf=', {'inf': ''}] 89 | ]; 90 | // }}} 91 | 92 | var qsNoMungeTestCases = [ 93 | ['', {}], 94 | ['foo=bar&foo=baz', {'foo': ['bar', 'baz']}], 95 | ['blah=burp', {'blah': 'burp'}], 96 | ['gragh=1&gragh=3&goo=2', {'gragh': ['1', '3'], 'goo': '2'}], 97 | ['frappucino=muffin&goat%5B%5D=scone&pond=moose', 98 | {'frappucino': 'muffin', 'goat[]': 'scone', 'pond': 'moose'}], 99 | ['trololol=yes&lololo=no', {'trololol': 'yes', 'lololo': 'no'}] 100 | ]; 101 | 102 | test('qs.parse - simple example', function (t) { 103 | t.strictEqual('918854443121279438895193', 104 | qs.parse('id=918854443121279438895193').id); 105 | t.end(); 106 | }); 107 | 108 | test('qs.parse - test that the canonical qs is parsed properly', function (t) { 109 | qsTestCases.forEach(function(testCase) { 110 | t.deepEqual(testCase[2], qs.parse(testCase[0])); 111 | }); 112 | t.end(); 113 | }); 114 | 115 | test('qs.parse - test that the colon test cases can do the same', function (t) { 116 | qsColonTestCases.forEach(function(testCase) { 117 | t.deepEqual(testCase[2], qs.parse(testCase[0], ';', ':')); 118 | }); 119 | t.end(); 120 | }); 121 | 122 | test('qs.parse - test the weird objects, that they get parsed properly', function (t) { 123 | qsWeirdObjects.forEach(function(testCase) { 124 | t.deepEqual(testCase[2], qs.parse(testCase[1])); 125 | }); 126 | t.end(); 127 | }); 128 | 129 | test('qs.stringify - simple example', function (t) { 130 | qsNoMungeTestCases.forEach(function(testCase) { 131 | t.deepEqual(testCase[0], qs.stringify(testCase[1], '&', '=', false)); 132 | }); 133 | t.end(); 134 | }) 135 | 136 | test('qs.parse - test the nested qs-in-qs case', function (t) { 137 | var f = qs.parse('a=b&q=x%3Dy%26y%3Dz'); 138 | f.q = qs.parse(f.q); 139 | t.deepEqual(f, { a: 'b', q: { x: 'y', y: 'z' } }); 140 | t.end(); 141 | }); 142 | 143 | test('qs.parse - nested in colon', function (t) { 144 | var f = qs.parse('a:b;q:x%3Ay%3By%3Az', ';', ':'); 145 | f.q = qs.parse(f.q, ';', ':'); 146 | t.deepEqual(f, { a: 'b', q: { x: 'y', y: 'z' } }); 147 | t.end(); 148 | }); 149 | 150 | test('qs.stringify - now test stringifying', function (t) { 151 | qsTestCases.forEach(function(testCase) { 152 | t.equal(testCase[1], qs.stringify(testCase[2])); 153 | }); 154 | 155 | qsColonTestCases.forEach(function(testCase) { 156 | t.equal(testCase[1], qs.stringify(testCase[2], ';', ':')); 157 | }); 158 | 159 | qsWeirdObjects.forEach(function(testCase) { 160 | t.equal(testCase[1], qs.stringify(testCase[0])); 161 | }); 162 | 163 | t.end(); 164 | }); 165 | 166 | test('qs.stringify - nested', function (t) { 167 | var f = qs.stringify({ 168 | a: 'b', 169 | q: qs.stringify({ 170 | x: 'y', 171 | y: 'z' 172 | }) 173 | }); 174 | t.equal(f, 'a=b&q=x%3Dy%26y%3Dz'); 175 | t.end(); 176 | }); 177 | 178 | test('qs.parse - do not throw on undefined input', function (t) { 179 | t.doesNotThrow(function() { 180 | qs.parse(undefined); 181 | }); 182 | t.end(); 183 | }); 184 | 185 | test('qs.stringify - nested in colon', function (t) { 186 | var f = qs.stringify({ 187 | a: 'b', 188 | q: qs.stringify({ 189 | x: 'y', 190 | y: 'z' 191 | }, ';', ':') 192 | }, ';', ':'); 193 | t.equal(f, 'a:b;q:x%3Ay%3By%3Az'); 194 | t.end(); 195 | }); 196 | 197 | test('qs.parse - on nothing', function (t) { 198 | t.deepEqual({}, qs.parse()); 199 | t.end(); 200 | }); 201 | 202 | // Test limiting 203 | test('qs.parse - test limiting', function (t) { 204 | t.equal( 205 | Object.keys(qs.parse('a=1&b=1&c=1', null, null, { maxKeys: 1 })).length, 206 | 1); 207 | t.end(); 208 | }); 209 | 210 | test('qs.parse - Test removing limit', function (t) { 211 | function testUnlimitedKeys() { 212 | var query = {}, 213 | url; 214 | 215 | for (var i = 0; i < 2000; i++) query[i] = i; 216 | 217 | url = qs.stringify(query); 218 | 219 | t.equal( 220 | Object.keys(qs.parse(url, null, null, { maxKeys: 0 })).length, 221 | 2000); 222 | } 223 | testUnlimitedKeys(); 224 | 225 | t.end(); 226 | }); 227 | 228 | test('qs.unescapeBuffer - basic', function (t) { 229 | var b = qs.unescapeBuffer('%d3%f2Ug%1f6v%24%5e%98%cb' + 230 | '%0d%ac%a2%2f%9d%eb%d8%a2%e6'); 231 | // 232 | t.equal(0xd3, b[0]); 233 | t.equal(0xf2, b[1]); 234 | t.equal(0x55, b[2]); 235 | t.equal(0x67, b[3]); 236 | t.equal(0x1f, b[4]); 237 | t.equal(0x36, b[5]); 238 | t.equal(0x76, b[6]); 239 | t.equal(0x24, b[7]); 240 | t.equal(0x5e, b[8]); 241 | t.equal(0x98, b[9]); 242 | t.equal(0xcb, b[10]); 243 | t.equal(0x0d, b[11]); 244 | t.equal(0xac, b[12]); 245 | t.equal(0xa2, b[13]); 246 | t.equal(0x2f, b[14]); 247 | t.equal(0x9d, b[15]); 248 | t.equal(0xeb, b[16]); 249 | t.equal(0xd8, b[17]); 250 | t.equal(0xa2, b[18]); 251 | t.equal(0xe6, b[19]); 252 | 253 | t.end(); 254 | }); 255 | -------------------------------------------------------------------------------- /test/browser/path-simple.js: -------------------------------------------------------------------------------- 1 | // Copyright Joyent, Inc. and other Node contributors. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the 5 | // "Software"), to deal in the Software without restriction, including 6 | // without limitation the rights to use, copy, modify, merge, publish, 7 | // distribute, sublicense, and/or sell copies of the Software, and to permit 8 | // persons to whom the Software is furnished to do so, subject to the 9 | // following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included 12 | // in all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 17 | // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 20 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | var test = require('tape'); 23 | 24 | var path = require('path'); 25 | 26 | test('path.basename', function (t) { 27 | t.equal(path.basename(''), ''); 28 | t.equal(path.basename('/dir/basename.ext'), 'basename.ext'); 29 | t.equal(path.basename('/basename.ext'), 'basename.ext'); 30 | t.equal(path.basename('basename.ext'), 'basename.ext'); 31 | t.equal(path.basename('basename.ext/'), 'basename.ext'); 32 | t.equal(path.basename('basename.ext//'), 'basename.ext'); 33 | 34 | t.equal(path.basename('\\dir\\basename.ext'), '\\dir\\basename.ext'); 35 | t.equal(path.basename('\\basename.ext'), '\\basename.ext'); 36 | t.equal(path.basename('basename.ext'), 'basename.ext'); 37 | t.equal(path.basename('basename.ext\\'), 'basename.ext\\'); 38 | t.equal(path.basename('basename.ext\\\\'), 'basename.ext\\\\'); 39 | 40 | t.end(); 41 | }); 42 | 43 | test('path.extname', function (t) { 44 | t.equal(path.dirname('/a/b/'), '/a'); 45 | t.equal(path.dirname('/a/b'), '/a'); 46 | t.equal(path.dirname('/a'), '/'); 47 | t.equal(path.dirname(''), '.'); 48 | t.equal(path.dirname('/'), '/'); 49 | t.equal(path.dirname('////'), '/'); 50 | 51 | t.equal(path.extname(''), ''); 52 | t.equal(path.extname('/path/to/file'), ''); 53 | t.equal(path.extname('/path/to/file.ext'), '.ext'); 54 | t.equal(path.extname('/path.to/file.ext'), '.ext'); 55 | t.equal(path.extname('/path.to/file'), ''); 56 | t.equal(path.extname('/path.to/.file'), ''); 57 | t.equal(path.extname('/path.to/.file.ext'), '.ext'); 58 | t.equal(path.extname('/path/to/f.ext'), '.ext'); 59 | t.equal(path.extname('/path/to/..ext'), '.ext'); 60 | t.equal(path.extname('file'), ''); 61 | t.equal(path.extname('file.ext'), '.ext'); 62 | t.equal(path.extname('.file'), ''); 63 | t.equal(path.extname('.file.ext'), '.ext'); 64 | t.equal(path.extname('/file'), ''); 65 | t.equal(path.extname('/file.ext'), '.ext'); 66 | t.equal(path.extname('/.file'), ''); 67 | t.equal(path.extname('/.file.ext'), '.ext'); 68 | t.equal(path.extname('.path/file.ext'), '.ext'); 69 | t.equal(path.extname('file.ext.ext'), '.ext'); 70 | t.equal(path.extname('file.'), '.'); 71 | t.equal(path.extname('.'), ''); 72 | t.equal(path.extname('./'), ''); 73 | t.equal(path.extname('.file.ext'), '.ext'); 74 | t.equal(path.extname('.file'), ''); 75 | t.equal(path.extname('.file.'), '.'); 76 | t.equal(path.extname('.file..'), '.'); 77 | t.equal(path.extname('..'), ''); 78 | t.equal(path.extname('../'), ''); 79 | t.equal(path.extname('..file.ext'), '.ext'); 80 | t.equal(path.extname('..file'), '.file'); 81 | t.equal(path.extname('..file.'), '.'); 82 | t.equal(path.extname('..file..'), '.'); 83 | t.equal(path.extname('...'), '.'); 84 | t.equal(path.extname('...ext'), '.ext'); 85 | t.equal(path.extname('....'), '.'); 86 | t.equal(path.extname('file.ext/'), '.ext'); 87 | t.equal(path.extname('file.ext//'), '.ext'); 88 | t.equal(path.extname('file/'), ''); 89 | t.equal(path.extname('file//'), ''); 90 | t.equal(path.extname('file./'), '.'); 91 | t.equal(path.extname('file.//'), '.'); 92 | 93 | t.equal(path.extname('.\\'), ''); 94 | t.equal(path.extname('..\\'), '.\\'); 95 | t.equal(path.extname('file.ext\\'), '.ext\\'); 96 | t.equal(path.extname('file.ext\\\\'), '.ext\\\\'); 97 | t.equal(path.extname('file\\'), ''); 98 | t.equal(path.extname('file\\\\'), ''); 99 | t.equal(path.extname('file.\\'), '.\\'); 100 | t.equal(path.extname('file.\\\\'), '.\\\\'); 101 | 102 | t.end(); 103 | }); 104 | 105 | test('path.join', function (t) { 106 | var joinTests = 107 | // arguments result 108 | [[['.', 'x/b', '..', '/b/c.js'], 'x/b/c.js'], 109 | [['/.', 'x/b', '..', '/b/c.js'], '/x/b/c.js'], 110 | [['/foo', '../../../bar'], '/bar'], 111 | [['foo', '../../../bar'], '../../bar'], 112 | [['foo/', '../../../bar'], '../../bar'], 113 | [['foo/x', '../../../bar'], '../bar'], 114 | [['foo/x', './bar'], 'foo/x/bar'], 115 | [['foo/x/', './bar'], 'foo/x/bar'], 116 | [['foo/x/', '.', 'bar'], 'foo/x/bar'], 117 | [['./'], './'], 118 | [['.', './'], './'], 119 | [['.', '.', '.'], '.'], 120 | [['.', './', '.'], '.'], 121 | [['.', '/./', '.'], '.'], 122 | [['.', '/////./', '.'], '.'], 123 | [['.'], '.'], 124 | [['', '.'], '.'], 125 | [['', 'foo'], 'foo'], 126 | [['foo', '/bar'], 'foo/bar'], 127 | [['', '/foo'], '/foo'], 128 | [['', '', '/foo'], '/foo'], 129 | [['', '', 'foo'], 'foo'], 130 | [['foo', ''], 'foo'], 131 | [['foo/', ''], 'foo/'], 132 | [['foo', '', '/bar'], 'foo/bar'], 133 | [['./', '..', '/foo'], '../foo'], 134 | [['./', '..', '..', '/foo'], '../../foo'], 135 | [['.', '..', '..', '/foo'], '../../foo'], 136 | [['', '..', '..', '/foo'], '../../foo'], 137 | [['/'], '/'], 138 | [['/', '.'], '/'], 139 | [['/', '..'], '/'], 140 | [['/', '..', '..'], '/'], 141 | [[''], '.'], 142 | [['', ''], '.'], 143 | [[' /foo'], ' /foo'], 144 | [[' ', 'foo'], ' /foo'], 145 | [[' ', '.'], ' '], 146 | [[' ', '/'], ' /'], 147 | [[' ', ''], ' '], 148 | [['/', 'foo'], '/foo'], 149 | [['/', '/foo'], '/foo'], 150 | [['/', '//foo'], '/foo'], 151 | [['/', '', '/foo'], '/foo'], 152 | [['', '/', 'foo'], '/foo'], 153 | [['', '/', '/foo'], '/foo'] 154 | ]; 155 | 156 | // Run the join tests. 157 | joinTests.forEach(function(test) { 158 | var actual = path.join.apply(path, test[0]); 159 | var expected = test[1]; 160 | t.equal(actual, expected); 161 | }); 162 | 163 | var joinThrowTests = [true, false, 7, null, {}, undefined, [], NaN]; 164 | joinThrowTests.forEach(function(test) { 165 | t.throws(function() { 166 | path.join(test); 167 | }, TypeError); 168 | t.throws(function() { 169 | path.resolve(test); 170 | }, TypeError); 171 | }); 172 | 173 | t.end(); 174 | }); 175 | 176 | test('path.normalize', function (t) { 177 | t.equal(path.normalize('./fixtures///b/../b/c.js'), 178 | 'fixtures/b/c.js'); 179 | t.equal(path.normalize('/foo/../../../bar'), '/bar'); 180 | t.equal(path.normalize('a//b//../b'), 'a/b'); 181 | t.equal(path.normalize('a//b//./c'), 'a/b/c'); 182 | t.equal(path.normalize('a//b//.'), 'a/b'); 183 | 184 | t.end(); 185 | }); 186 | 187 | test('path.resolve', function (t) { 188 | var resolveTests = 189 | // arguments result 190 | [[['/var/lib', '../', 'file/'], '/var/file'], 191 | [['/var/lib', '/../', 'file/'], '/file'], 192 | [['/some/dir', '.', '/absolute/'], '/absolute']]; 193 | 194 | resolveTests.forEach(function(test) { 195 | var actual = path.resolve.apply(path, test[0]); 196 | var expected = test[1]; 197 | t.equal(actual, expected); 198 | }); 199 | 200 | t.end(); 201 | }); 202 | 203 | test('path.isAbsolute', function (t) { 204 | t.equal(path.isAbsolute('/home/foo'), true); 205 | t.equal(path.isAbsolute('/home/foo/..'), true); 206 | t.equal(path.isAbsolute('bar/'), false); 207 | t.equal(path.isAbsolute('./baz'), false); 208 | 209 | t.end(); 210 | }); 211 | 212 | test('path.relative', function (t) { 213 | var relativeTests = 214 | // arguments result 215 | [['/var/lib', '/var', '..'], 216 | ['/var/lib', '/bin', '../../bin'], 217 | ['/var/lib', '/var/lib', ''], 218 | ['/var/lib', '/var/apache', '../apache'], 219 | ['/var/', '/var/lib', 'lib'], 220 | ['/', '/var/lib', 'var/lib']]; 221 | 222 | relativeTests.forEach(function(test) { 223 | var actual = path.relative(test[0], test[1]); 224 | var expected = test[2]; 225 | t.equal(actual, expected); 226 | }); 227 | 228 | t.end(); 229 | }); 230 | 231 | test('path.sep', function (t) { 232 | t.equal(path.sep, '/'); 233 | 234 | t.end(); 235 | }); 236 | 237 | test('path.delimiter', function (t) { 238 | t.equal(path.delimiter, ':'); 239 | 240 | t.end(); 241 | }); 242 | -------------------------------------------------------------------------------- /test/browser/stream2-writable.js: -------------------------------------------------------------------------------- 1 | // Copyright Joyent, Inc. and other Node contributors. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the 5 | // "Software"), to deal in the Software without restriction, including 6 | // without limitation the rights to use, copy, modify, merge, publish, 7 | // distribute, sublicense, and/or sell copies of the Software, and to permit 8 | // persons to whom the Software is furnished to do so, subject to the 9 | // following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included 12 | // in all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 17 | // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 20 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | var test = require('tape'); 23 | var R = require('stream').Readable; 24 | var W = require('stream').Writable; 25 | var D = require('stream').Duplex; 26 | var timers = require('timers'); 27 | var Buffer = require('buffer').Buffer; 28 | 29 | var stdout = new R(); 30 | 31 | var util = require('util'); 32 | util.inherits(TestWriter, W); 33 | 34 | function TestWriter() { 35 | W.apply(this, arguments); 36 | this.buffer = []; 37 | this.written = 0; 38 | } 39 | 40 | TestWriter.prototype._write = function(chunk, encoding, cb) { 41 | // simulate a small unpredictable latency 42 | setTimeout((function() { 43 | this.buffer.push(chunk.toString()); 44 | this.written += chunk.length; 45 | cb(); 46 | }).bind(this), Math.floor(Math.random() * 10)); 47 | }; 48 | 49 | var chunks = new Array(50); 50 | for (var i = 0; i < chunks.length; i++) { 51 | chunks[i] = new Array(i + 1).join('x'); 52 | } 53 | 54 | test('write fast', function(t) { 55 | var tw = new TestWriter({ 56 | highWaterMark: 100 57 | }); 58 | 59 | tw.on('finish', function() { 60 | t.same(tw.buffer, chunks, 'got chunks in the right order'); 61 | t.end(); 62 | }); 63 | 64 | chunks.forEach(function(chunk) { 65 | // screw backpressure. Just buffer it all up. 66 | tw.write(chunk); 67 | }); 68 | tw.end(); 69 | }); 70 | 71 | test('write slow', function(t) { 72 | var tw = new TestWriter({ 73 | highWaterMark: 100 74 | }); 75 | 76 | tw.on('finish', function() { 77 | t.same(tw.buffer, chunks, 'got chunks in the right order'); 78 | t.end(); 79 | }); 80 | 81 | var i = 0; 82 | (function W() { 83 | tw.write(chunks[i++]); 84 | if (i < chunks.length) 85 | setTimeout(W, 10); 86 | else 87 | tw.end(); 88 | })(); 89 | }); 90 | 91 | test('write backpressure', function(t) { 92 | var tw = new TestWriter({ 93 | highWaterMark: 50 94 | }); 95 | 96 | var drains = 0; 97 | 98 | tw.on('finish', function() { 99 | t.same(tw.buffer, chunks, 'got chunks in the right order'); 100 | t.equal(drains, 17); 101 | t.end(); 102 | }); 103 | 104 | tw.on('drain', function() { 105 | drains++; 106 | }); 107 | 108 | var i = 0; 109 | (function W() { 110 | do { 111 | var ret = tw.write(chunks[i++]); 112 | } while (ret !== false && i < chunks.length); 113 | 114 | if (i < chunks.length) { 115 | t.ok(tw._writableState.length >= 50); 116 | tw.once('drain', W); 117 | } else { 118 | tw.end(); 119 | } 120 | })(); 121 | }); 122 | 123 | test('write bufferize', function(t) { 124 | var tw = new TestWriter({ 125 | highWaterMark: 100 126 | }); 127 | 128 | var encodings = 129 | [ 'hex', 130 | 'utf8', 131 | 'utf-8', 132 | 'ascii', 133 | 'binary', 134 | 'base64', 135 | undefined ]; 136 | 137 | tw.on('finish', function() { 138 | t.same(tw.buffer, chunks, 'got the expected chunks'); 139 | }); 140 | 141 | chunks.forEach(function(chunk, i) { 142 | var enc = encodings[ i % encodings.length ]; 143 | chunk = new Buffer(chunk); 144 | tw.write(chunk.toString(enc), enc); 145 | }); 146 | t.end(); 147 | }); 148 | 149 | test('write no bufferize', function(t) { 150 | var tw = new TestWriter({ 151 | highWaterMark: 100, 152 | decodeStrings: false 153 | }); 154 | 155 | tw._write = function(chunk, encoding, cb) { 156 | t.ok(typeof chunk === 'string'); 157 | chunk = new Buffer(chunk, encoding); 158 | return TestWriter.prototype._write.call(this, chunk, encoding, cb); 159 | }; 160 | 161 | var encodings = 162 | [ 'hex', 163 | 'utf8', 164 | 'utf-8', 165 | 'ascii', 166 | 'binary', 167 | 'base64', 168 | undefined ]; 169 | 170 | tw.on('finish', function() { 171 | t.same(tw.buffer, chunks, 'got the expected chunks'); 172 | }); 173 | 174 | chunks.forEach(function(chunk, i) { 175 | var enc = encodings[ i % encodings.length ]; 176 | chunk = new Buffer(chunk); 177 | tw.write(chunk.toString(enc), enc); 178 | }); 179 | t.end(); 180 | }); 181 | 182 | test('write callbacks', function (t) { 183 | var callbacks = chunks.map(function(chunk, i) { 184 | return [i, function(er) { 185 | callbacks._called[i] = chunk; 186 | }]; 187 | }).reduce(function(set, x) { 188 | set['callback-' + x[0]] = x[1]; 189 | return set; 190 | }, {}); 191 | callbacks._called = []; 192 | 193 | var tw = new TestWriter({ 194 | highWaterMark: 100 195 | }); 196 | 197 | tw.on('finish', function() { 198 | timers.setImmediate(function() { 199 | t.same(tw.buffer, chunks, 'got chunks in the right order'); 200 | t.same(callbacks._called, chunks, 'called all callbacks'); 201 | t.end(); 202 | }); 203 | }); 204 | 205 | chunks.forEach(function(chunk, i) { 206 | tw.write(chunk, callbacks['callback-' + i]); 207 | }); 208 | tw.end(); 209 | }); 210 | 211 | test('end callback', function (t) { 212 | var tw = new TestWriter(); 213 | tw.end(function () { 214 | t.end(); 215 | }); 216 | }); 217 | 218 | test('end callback with chunk', function (t) { 219 | var tw = new TestWriter(); 220 | tw.end(new Buffer('hello world'), function () { 221 | t.end(); 222 | }); 223 | }); 224 | 225 | test('end callback with chunk and encoding', function (t) { 226 | var tw = new TestWriter(); 227 | tw.end('hello world', 'ascii', function () { 228 | t.end(); 229 | }); 230 | }); 231 | 232 | test('end callback after .write() call', function (t) { 233 | var tw = new TestWriter(); 234 | tw.write(new Buffer('hello world')); 235 | tw.end(function () { 236 | t.end(); 237 | }); 238 | }); 239 | 240 | test('end callback called after write callback', function (t) { 241 | var tw = new TestWriter(); 242 | var writeCalledback = false; 243 | tw.write(new Buffer('hello world'), function() { 244 | writeCalledback = true; 245 | }); 246 | tw.end(function () { 247 | t.equal(writeCalledback, true); 248 | t.end(); 249 | }); 250 | }); 251 | 252 | test('encoding should be ignored for buffers', function(t) { 253 | var tw = new W(); 254 | var hex = '018b5e9a8f6236ffe30e31baf80d2cf6eb'; 255 | tw._write = function(chunk, encoding, cb) { 256 | t.equal(chunk.toString('hex'), hex); 257 | t.end(); 258 | }; 259 | var buf = new Buffer(hex, 'hex'); 260 | tw.write(buf, 'binary'); 261 | }); 262 | 263 | test('writables are not pipable', function(t) { 264 | var w = new W(); 265 | w._write = function() {}; 266 | var gotError = false; 267 | w.on('error', function(er) { 268 | gotError = true; 269 | }); 270 | w.pipe(stdout); 271 | t.ok(gotError); 272 | t.end(); 273 | }); 274 | 275 | test('duplexes are pipable', function(t) { 276 | var d = new D(); 277 | d._read = function() {}; 278 | d._write = function() {}; 279 | var gotError = false; 280 | d.on('error', function(er) { 281 | gotError = true; 282 | }); 283 | d.pipe(stdout); 284 | t.ok(!gotError); 285 | t.end(); 286 | }); 287 | 288 | test('end(chunk) two times is an error', function(t) { 289 | var w = new W(); 290 | w._write = function() {}; 291 | var gotError = false; 292 | w.on('error', function(er) { 293 | gotError = true; 294 | t.equal(er.message, 'write after end'); 295 | }); 296 | w.end('this is the end'); 297 | w.end('and so is this'); 298 | timers.setImmediate(function() { 299 | t.ok(gotError); 300 | t.end(); 301 | }); 302 | }); 303 | 304 | test('dont end while writing', function(t) { 305 | var w = new W(); 306 | var wrote = false; 307 | w._write = function(chunk, e, cb) { 308 | t.ok(!this.writing); 309 | wrote = true; 310 | this.writing = true; 311 | setTimeout(function() { 312 | this.writing = false; 313 | cb(); 314 | }); 315 | }; 316 | w.on('finish', function() { 317 | t.ok(wrote); 318 | t.end(); 319 | }); 320 | w.write(Buffer(0)); 321 | w.end(); 322 | }); 323 | 324 | test('finish does not come before write cb', function(t) { 325 | var w = new W(); 326 | var writeCb = false; 327 | w._write = function(chunk, e, cb) { 328 | setTimeout(function() { 329 | writeCb = true; 330 | cb(); 331 | }, 10); 332 | }; 333 | w.on('finish', function() { 334 | t.ok(writeCb); 335 | t.end(); 336 | }); 337 | w.write(Buffer(0)); 338 | w.end(); 339 | }); 340 | -------------------------------------------------------------------------------- /test/browser/stream2-basic.js: -------------------------------------------------------------------------------- 1 | // Copyright Joyent, Inc. and other Node contributors. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the 5 | // "Software"), to deal in the Software without restriction, including 6 | // without limitation the rights to use, copy, modify, merge, publish, 7 | // distribute, sublicense, and/or sell copies of the Software, and to permit 8 | // persons to whom the Software is furnished to do so, subject to the 9 | // following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included 12 | // in all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 17 | // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 20 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | var test = require('tape'); 23 | var Buffer = require('buffer').Buffer; 24 | 25 | var R = require('stream').Readable; 26 | var timers = require('timers'); 27 | 28 | var util = require('util'); 29 | var EE = require('events').EventEmitter; 30 | 31 | function TestReader(n) { 32 | R.apply(this); 33 | this._buffer = new Buffer(n || 100); 34 | this._buffer.fill('x'); 35 | this._pos = 0; 36 | this._bufs = 10; 37 | } 38 | 39 | util.inherits(TestReader, R); 40 | 41 | TestReader.prototype.read = function(n) { 42 | if (n === 0) return null; 43 | var max = this._buffer.length - this._pos; 44 | n = n || max; 45 | n = Math.max(n, 0); 46 | var toRead = Math.min(n, max); 47 | if (toRead === 0) { 48 | // simulate the read buffer filling up with some more bytes some time 49 | // in the future. 50 | setTimeout((function() { 51 | this._pos = 0; 52 | this._bufs -= 1; 53 | if (this._bufs <= 0) { 54 | // read them all! 55 | if (!this.ended) { 56 | this.emit('end'); 57 | this.ended = true; 58 | } 59 | } else { 60 | this.emit('readable'); 61 | } 62 | }).bind(this), 10); 63 | return null; 64 | } 65 | 66 | var ret = this._buffer.slice(this._pos, this._pos + toRead); 67 | this._pos += toRead; 68 | return ret; 69 | }; 70 | 71 | ///// 72 | 73 | function TestWriter() { 74 | EE.apply(this); 75 | this.received = []; 76 | this.flush = false; 77 | } 78 | 79 | util.inherits(TestWriter, EE); 80 | 81 | TestWriter.prototype.write = function(c) { 82 | this.received.push(c.toString()); 83 | this.emit('write', c); 84 | return true; 85 | }; 86 | 87 | TestWriter.prototype.end = function(c) { 88 | if (c) this.write(c); 89 | this.emit('end', this.received); 90 | }; 91 | 92 | test('a most basic test', function(t) { 93 | var r = new TestReader(20); 94 | 95 | var reads = []; 96 | var expect = [ 'x', 97 | 'xx', 98 | 'xxx', 99 | 'xxxx', 100 | 'xxxxx', 101 | 'xxxxx', 102 | 'xxxxxxxx', 103 | 'xxxxxxxxx', 104 | 'xxx', 105 | 'xxxxxxxxxxxx', 106 | 'xxxxxxxx', 107 | 'xxxxxxxxxxxxxxx', 108 | 'xxxxx', 109 | 'xxxxxxxxxxxxxxxxxx', 110 | 'xx', 111 | 'xxxxxxxxxxxxxxxxxxxx', 112 | 'xxxxxxxxxxxxxxxxxxxx', 113 | 'xxxxxxxxxxxxxxxxxxxx', 114 | 'xxxxxxxxxxxxxxxxxxxx', 115 | 'xxxxxxxxxxxxxxxxxxxx' ]; 116 | 117 | r.on('end', function() { 118 | t.same(reads, expect); 119 | t.end(); 120 | }); 121 | 122 | var readSize = 1; 123 | function flow() { 124 | var res; 125 | while (null !== (res = r.read(readSize++))) { 126 | reads.push(res.toString()); 127 | } 128 | r.once('readable', flow); 129 | } 130 | 131 | flow(); 132 | }); 133 | 134 | test('pipe', function(t) { 135 | var r = new TestReader(5); 136 | 137 | var expect = [ 'xxxxx', 138 | 'xxxxx', 139 | 'xxxxx', 140 | 'xxxxx', 141 | 'xxxxx', 142 | 'xxxxx', 143 | 'xxxxx', 144 | 'xxxxx', 145 | 'xxxxx', 146 | 'xxxxx' ] 147 | 148 | var w = new TestWriter; 149 | var flush = true; 150 | 151 | w.on('end', function(received) { 152 | t.same(received, expect); 153 | t.end(); 154 | }); 155 | 156 | r.pipe(w); 157 | }); 158 | 159 | 160 | 161 | [1,2,3,4,5,6,7,8,9].forEach(function(SPLIT) { 162 | test('unpipe', function(t) { 163 | var r = new TestReader(5); 164 | 165 | // unpipe after 3 writes, then write to another stream instead. 166 | var expect = [ 'xxxxx', 167 | 'xxxxx', 168 | 'xxxxx', 169 | 'xxxxx', 170 | 'xxxxx', 171 | 'xxxxx', 172 | 'xxxxx', 173 | 'xxxxx', 174 | 'xxxxx', 175 | 'xxxxx' ]; 176 | expect = [ expect.slice(0, SPLIT), expect.slice(SPLIT) ]; 177 | 178 | var w = [ new TestWriter(), new TestWriter() ]; 179 | 180 | var writes = SPLIT; 181 | w[0].on('write', function() { 182 | if (--writes === 0) { 183 | r.unpipe(); 184 | t.equal(r._readableState.pipes, null); 185 | w[0].end(); 186 | r.pipe(w[1]); 187 | t.equal(r._readableState.pipes, w[1]); 188 | } 189 | }); 190 | 191 | var ended = 0; 192 | 193 | var ended0 = false; 194 | var ended1 = false; 195 | w[0].on('end', function(results) { 196 | t.equal(ended0, false); 197 | ended0 = true; 198 | ended++; 199 | t.same(results, expect[0]); 200 | }); 201 | 202 | w[1].on('end', function(results) { 203 | t.equal(ended1, false); 204 | ended1 = true; 205 | ended++; 206 | t.equal(ended, 2); 207 | t.same(results, expect[1]); 208 | t.end(); 209 | }); 210 | 211 | r.pipe(w[0]); 212 | }); 213 | }); 214 | 215 | 216 | // both writers should get the same exact data. 217 | test('multipipe', function(t) { 218 | var r = new TestReader(5); 219 | var w = [ new TestWriter, new TestWriter ]; 220 | 221 | var expect = [ 'xxxxx', 222 | 'xxxxx', 223 | 'xxxxx', 224 | 'xxxxx', 225 | 'xxxxx', 226 | 'xxxxx', 227 | 'xxxxx', 228 | 'xxxxx', 229 | 'xxxxx', 230 | 'xxxxx' ]; 231 | 232 | var c = 2; 233 | w[0].on('end', function(received) { 234 | t.same(received, expect, 'first'); 235 | if (--c === 0) t.end(); 236 | }); 237 | w[1].on('end', function(received) { 238 | t.same(received, expect, 'second'); 239 | if (--c === 0) t.end(); 240 | }); 241 | 242 | r.pipe(w[0]); 243 | r.pipe(w[1]); 244 | }); 245 | 246 | 247 | [1,2,3,4,5,6,7,8,9].forEach(function(SPLIT) { 248 | test('multi-unpipe', function(t) { 249 | var r = new TestReader(5); 250 | 251 | // unpipe after 3 writes, then write to another stream instead. 252 | var expect = [ 'xxxxx', 253 | 'xxxxx', 254 | 'xxxxx', 255 | 'xxxxx', 256 | 'xxxxx', 257 | 'xxxxx', 258 | 'xxxxx', 259 | 'xxxxx', 260 | 'xxxxx', 261 | 'xxxxx' ]; 262 | expect = [ expect.slice(0, SPLIT), expect.slice(SPLIT) ]; 263 | 264 | var w = [ new TestWriter(), new TestWriter(), new TestWriter() ]; 265 | 266 | var writes = SPLIT; 267 | w[0].on('write', function() { 268 | if (--writes === 0) { 269 | r.unpipe(); 270 | w[0].end(); 271 | r.pipe(w[1]); 272 | } 273 | }); 274 | 275 | var ended = 0; 276 | 277 | w[0].on('end', function(results) { 278 | ended++; 279 | t.same(results, expect[0]); 280 | }); 281 | 282 | w[1].on('end', function(results) { 283 | ended++; 284 | t.equal(ended, 2); 285 | t.same(results, expect[1]); 286 | t.end(); 287 | }); 288 | 289 | r.pipe(w[0]); 290 | r.pipe(w[2]); 291 | }); 292 | }); 293 | 294 | test('back pressure respected', function (t) { 295 | function noop() {} 296 | 297 | var r = new R({ objectMode: true }); 298 | r._read = noop; 299 | var counter = 0; 300 | r.push(["one"]); 301 | r.push(["two"]); 302 | r.push(["three"]); 303 | r.push(["four"]); 304 | r.push(null); 305 | 306 | var w1 = new R(); 307 | w1.write = function (chunk) { 308 | t.equal(chunk[0], "one"); 309 | w1.emit("close"); 310 | timers.setImmediate(function () { 311 | r.pipe(w2); 312 | r.pipe(w3); 313 | }) 314 | }; 315 | w1.end = noop; 316 | 317 | r.pipe(w1); 318 | 319 | var expected = ["two", "two", "three", "three", "four", "four"]; 320 | 321 | var w2 = new R(); 322 | w2.write = function (chunk) { 323 | t.equal(chunk[0], expected.shift()); 324 | t.equal(counter, 0); 325 | 326 | counter++; 327 | 328 | if (chunk[0] === "four") { 329 | return true; 330 | } 331 | 332 | setTimeout(function () { 333 | counter--; 334 | w2.emit("drain"); 335 | }, 10); 336 | 337 | return false; 338 | } 339 | w2.end = noop; 340 | 341 | var w3 = new R(); 342 | w3.write = function (chunk) { 343 | t.equal(chunk[0], expected.shift()); 344 | t.equal(counter, 1); 345 | 346 | counter++; 347 | 348 | if (chunk[0] === "four") { 349 | return true; 350 | } 351 | 352 | setTimeout(function () { 353 | counter--; 354 | w3.emit("drain"); 355 | }, 50); 356 | 357 | return false; 358 | }; 359 | w3.end = function () { 360 | t.equal(counter, 2); 361 | t.equal(expected.length, 0); 362 | t.end(); 363 | }; 364 | }); 365 | 366 | test('read(0) for ended streams', function (t) { 367 | var r = new R(); 368 | var written = false; 369 | var ended = false; 370 | r._read = function (n) {}; 371 | 372 | r.push(new Buffer("foo")); 373 | r.push(null); 374 | 375 | var v = r.read(0); 376 | 377 | t.equal(v, null); 378 | 379 | var w = new R(); 380 | 381 | w.write = function (buffer) { 382 | written = true; 383 | t.equal(ended, false); 384 | t.equal(buffer.toString(), "foo") 385 | }; 386 | 387 | w.end = function () { 388 | ended = true; 389 | t.equal(written, true); 390 | t.end(); 391 | }; 392 | 393 | r.pipe(w); 394 | }) 395 | 396 | test('sync _read ending', function (t) { 397 | var r = new R(); 398 | var called = false; 399 | r._read = function (n) { 400 | r.push(null); 401 | }; 402 | 403 | r.once('end', function () { 404 | called = true; 405 | }) 406 | 407 | r.read(); 408 | 409 | timers.setImmediate(function () { 410 | t.equal(called, true); 411 | t.end(); 412 | }) 413 | }); 414 | 415 | test('adding readable triggers data flow', function(t) { 416 | var r = new R({ highWaterMark: 5 }); 417 | var onReadable = false; 418 | var readCalled = 0; 419 | 420 | r._read = function(n) { 421 | if (readCalled++ === 2) 422 | r.push(null); 423 | else 424 | r.push(new Buffer('asdf')); 425 | }; 426 | 427 | var called = false; 428 | r.on('readable', function() { 429 | onReadable = true; 430 | r.read(); 431 | }); 432 | 433 | r.on('end', function() { 434 | t.equal(readCalled, 3); 435 | t.ok(onReadable); 436 | t.end(); 437 | }); 438 | }); 439 | -------------------------------------------------------------------------------- /test/browser/stream2-transform.js: -------------------------------------------------------------------------------- 1 | // Copyright Joyent, Inc. and other Node contributors. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the 5 | // "Software"), to deal in the Software without restriction, including 6 | // without limitation the rights to use, copy, modify, merge, publish, 7 | // distribute, sublicense, and/or sell copies of the Software, and to permit 8 | // persons to whom the Software is furnished to do so, subject to the 9 | // following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included 12 | // in all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 17 | // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 20 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | var test = require('tape'); 23 | var Buffer = require('buffer').Buffer; 24 | var PassThrough = require('stream').PassThrough; 25 | var Transform = require('stream').Transform; 26 | var timers = require('timers'); 27 | 28 | test('writable side consumption', function(t) { 29 | var tx = new Transform({ 30 | highWaterMark: 10 31 | }); 32 | 33 | var transformed = 0; 34 | tx._transform = function(chunk, encoding, cb) { 35 | transformed += chunk.length; 36 | tx.push(chunk); 37 | cb(); 38 | }; 39 | 40 | for (var i = 1; i <= 10; i++) { 41 | tx.write(new Buffer(i)); 42 | } 43 | tx.end(); 44 | 45 | t.equal(tx._readableState.length, 10); 46 | t.equal(transformed, 10); 47 | t.equal(tx._transformState.writechunk.length, 5); 48 | t.same(tx._writableState.buffer.map(function(c) { 49 | return c.chunk.length; 50 | }), [6, 7, 8, 9, 10]); 51 | 52 | t.end(); 53 | }); 54 | 55 | test('passthrough', function(t) { 56 | var pt = new PassThrough(); 57 | 58 | pt.write(new Buffer('foog')); 59 | pt.write(new Buffer('bark')); 60 | pt.write(new Buffer('bazy')); 61 | pt.write(new Buffer('kuel')); 62 | pt.end(); 63 | 64 | t.equal(pt.read(5).toString(), 'foogb'); 65 | t.equal(pt.read(5).toString(), 'arkba'); 66 | t.equal(pt.read(5).toString(), 'zykue'); 67 | t.equal(pt.read(5).toString(), 'l'); 68 | t.end(); 69 | }); 70 | 71 | test('simple transform', function(t) { 72 | var pt = new Transform; 73 | pt._transform = function(c, e, cb) { 74 | var ret = new Buffer(c.length); 75 | ret.fill('x'); 76 | pt.push(ret); 77 | cb(); 78 | }; 79 | 80 | pt.write(new Buffer('foog')); 81 | pt.write(new Buffer('bark')); 82 | pt.write(new Buffer('bazy')); 83 | pt.write(new Buffer('kuel')); 84 | pt.end(); 85 | 86 | t.equal(pt.read(5).toString(), 'xxxxx'); 87 | t.equal(pt.read(5).toString(), 'xxxxx'); 88 | t.equal(pt.read(5).toString(), 'xxxxx'); 89 | t.equal(pt.read(5).toString(), 'x'); 90 | t.end(); 91 | }); 92 | 93 | test('async passthrough', function(t) { 94 | var pt = new Transform; 95 | pt._transform = function(chunk, encoding, cb) { 96 | setTimeout(function() { 97 | pt.push(chunk); 98 | cb(); 99 | }, 10); 100 | }; 101 | 102 | pt.write(new Buffer('foog')); 103 | pt.write(new Buffer('bark')); 104 | pt.write(new Buffer('bazy')); 105 | pt.write(new Buffer('kuel')); 106 | pt.end(); 107 | 108 | pt.on('finish', function() { 109 | t.equal(pt.read(5).toString(), 'foogb'); 110 | t.equal(pt.read(5).toString(), 'arkba'); 111 | t.equal(pt.read(5).toString(), 'zykue'); 112 | t.equal(pt.read(5).toString(), 'l'); 113 | t.end(); 114 | }); 115 | }); 116 | 117 | test('assymetric transform (expand)', function(t) { 118 | var pt = new Transform; 119 | 120 | // emit each chunk 2 times. 121 | pt._transform = function(chunk, encoding, cb) { 122 | setTimeout(function() { 123 | pt.push(chunk); 124 | setTimeout(function() { 125 | pt.push(chunk); 126 | cb(); 127 | }, 10) 128 | }, 10); 129 | }; 130 | 131 | pt.write(new Buffer('foog')); 132 | pt.write(new Buffer('bark')); 133 | pt.write(new Buffer('bazy')); 134 | pt.write(new Buffer('kuel')); 135 | pt.end(); 136 | 137 | pt.on('finish', function() { 138 | t.equal(pt.read(5).toString(), 'foogf'); 139 | t.equal(pt.read(5).toString(), 'oogba'); 140 | t.equal(pt.read(5).toString(), 'rkbar'); 141 | t.equal(pt.read(5).toString(), 'kbazy'); 142 | t.equal(pt.read(5).toString(), 'bazyk'); 143 | t.equal(pt.read(5).toString(), 'uelku'); 144 | t.equal(pt.read(5).toString(), 'el'); 145 | t.end(); 146 | }); 147 | }); 148 | 149 | test('assymetric transform (compress)', function(t) { 150 | var pt = new Transform; 151 | 152 | // each output is the first char of 3 consecutive chunks, 153 | // or whatever's left. 154 | pt.state = ''; 155 | 156 | pt._transform = function(chunk, encoding, cb) { 157 | if (!chunk) 158 | chunk = ''; 159 | var s = chunk.toString(); 160 | setTimeout((function() { 161 | this.state += s.charAt(0); 162 | if (this.state.length === 3) { 163 | pt.push(new Buffer(this.state)); 164 | this.state = ''; 165 | } 166 | cb(); 167 | }).bind(this), 10); 168 | }; 169 | 170 | pt._flush = function(cb) { 171 | // just output whatever we have. 172 | pt.push(new Buffer(this.state)); 173 | this.state = ''; 174 | cb(); 175 | }; 176 | 177 | pt.write(new Buffer('aaaa')); 178 | pt.write(new Buffer('bbbb')); 179 | pt.write(new Buffer('cccc')); 180 | pt.write(new Buffer('dddd')); 181 | pt.write(new Buffer('eeee')); 182 | pt.write(new Buffer('aaaa')); 183 | pt.write(new Buffer('bbbb')); 184 | pt.write(new Buffer('cccc')); 185 | pt.write(new Buffer('dddd')); 186 | pt.write(new Buffer('eeee')); 187 | pt.write(new Buffer('aaaa')); 188 | pt.write(new Buffer('bbbb')); 189 | pt.write(new Buffer('cccc')); 190 | pt.write(new Buffer('dddd')); 191 | pt.end(); 192 | 193 | // 'abcdeabcdeabcd' 194 | pt.on('finish', function() { 195 | t.equal(pt.read(5).toString(), 'abcde'); 196 | t.equal(pt.read(5).toString(), 'abcde'); 197 | t.equal(pt.read(5).toString(), 'abcd'); 198 | t.end(); 199 | }); 200 | }); 201 | 202 | // this tests for a stall when data is written to a full stream 203 | // that has empty transforms. 204 | test('complex transform', function(t) { 205 | var count = 0; 206 | var saved = null; 207 | var pt = new Transform({highWaterMark:3}); 208 | pt._transform = function(c, e, cb) { 209 | if (count++ === 1) 210 | saved = c; 211 | else { 212 | if (saved) { 213 | pt.push(saved); 214 | saved = null; 215 | } 216 | pt.push(c); 217 | } 218 | 219 | cb(); 220 | }; 221 | 222 | pt.once('readable', function() { 223 | timers.setImmediate(function() { 224 | pt.write(new Buffer('d')); 225 | pt.write(new Buffer('ef'), function() { 226 | pt.end(); 227 | t.end(); 228 | }); 229 | t.equal(pt.read().toString(), 'abc'); 230 | t.equal(pt.read().toString(), 'def'); 231 | t.equal(pt.read(), null); 232 | }); 233 | }); 234 | 235 | pt.write(new Buffer('abc')); 236 | }); 237 | 238 | 239 | test('passthrough event emission', function(t) { 240 | var pt = new PassThrough(); 241 | var emits = 0; 242 | pt.on('readable', function() { 243 | var state = pt._readableState; 244 | emits++; 245 | }); 246 | 247 | var i = 0; 248 | 249 | pt.write(new Buffer('foog')); 250 | 251 | pt.write(new Buffer('bark')); 252 | 253 | t.equal(emits, 1); 254 | 255 | t.equal(pt.read(5).toString(), 'foogb'); 256 | t.equal(pt.read(5) + '', 'null'); 257 | 258 | pt.write(new Buffer('bazy')); 259 | pt.write(new Buffer('kuel')); 260 | 261 | t.equal(emits, 2); 262 | 263 | t.equal(pt.read(5).toString(), 'arkba'); 264 | t.equal(pt.read(5).toString(), 'zykue'); 265 | t.equal(pt.read(5), null); 266 | 267 | pt.end(); 268 | 269 | t.equal(emits, 3); 270 | 271 | t.equal(pt.read(5).toString(), 'l'); 272 | t.equal(pt.read(5), null); 273 | 274 | t.equal(emits, 3); 275 | t.end(); 276 | }); 277 | 278 | test('passthrough event emission reordered', function(t) { 279 | var pt = new PassThrough; 280 | var emits = 0; 281 | pt.on('readable', function() { 282 | emits++; 283 | }); 284 | 285 | pt.write(new Buffer('foog')); 286 | pt.write(new Buffer('bark')); 287 | t.equal(emits, 1); 288 | 289 | t.equal(pt.read(5).toString(), 'foogb'); 290 | t.equal(pt.read(5), null); 291 | 292 | pt.once('readable', function() { 293 | t.equal(pt.read(5).toString(), 'arkba'); 294 | 295 | t.equal(pt.read(5), null); 296 | 297 | pt.once('readable', function() { 298 | t.equal(pt.read(5).toString(), 'zykue'); 299 | t.equal(pt.read(5), null); 300 | pt.once('readable', function() { 301 | t.equal(pt.read(5).toString(), 'l'); 302 | t.equal(pt.read(5), null); 303 | t.equal(emits, 4); 304 | t.end(); 305 | }); 306 | pt.end(); 307 | }); 308 | pt.write(new Buffer('kuel')); 309 | }); 310 | 311 | pt.write(new Buffer('bazy')); 312 | }); 313 | 314 | test('passthrough facaded', function(t) { 315 | var pt = new PassThrough; 316 | var datas = []; 317 | pt.on('data', function(chunk) { 318 | datas.push(chunk.toString()); 319 | }); 320 | 321 | pt.on('end', function() { 322 | t.same(datas, ['foog', 'bark', 'bazy', 'kuel']); 323 | t.end(); 324 | }); 325 | 326 | pt.write(new Buffer('foog')); 327 | setTimeout(function() { 328 | pt.write(new Buffer('bark')); 329 | setTimeout(function() { 330 | pt.write(new Buffer('bazy')); 331 | setTimeout(function() { 332 | pt.write(new Buffer('kuel')); 333 | setTimeout(function() { 334 | pt.end(); 335 | }, 10); 336 | }, 10); 337 | }, 10); 338 | }, 10); 339 | }); 340 | 341 | test('object transform (json parse)', function(t) { 342 | var jp = new Transform({ objectMode: true }); 343 | jp._transform = function(data, encoding, cb) { 344 | try { 345 | jp.push(JSON.parse(data)); 346 | cb(); 347 | } catch (er) { 348 | cb(er); 349 | } 350 | }; 351 | 352 | // anything except null/undefined is fine. 353 | // those are "magic" in the stream API, because they signal EOF. 354 | var objects = [ 355 | { foo: 'bar' }, 356 | 100, 357 | "string", 358 | { nested: { things: [ { foo: 'bar' }, 100, "string" ] } } 359 | ]; 360 | 361 | var ended = false; 362 | jp.on('end', function() { 363 | ended = true; 364 | }); 365 | 366 | objects.forEach(function(obj) { 367 | jp.write(JSON.stringify(obj)); 368 | var res = jp.read(); 369 | t.same(res, obj); 370 | }); 371 | 372 | jp.end(); 373 | 374 | timers.setImmediate(function() { 375 | t.ok(ended); 376 | t.end(); 377 | }) 378 | }); 379 | 380 | test('object transform (json stringify)', function(t) { 381 | var js = new Transform({ objectMode: true }); 382 | js._transform = function(data, encoding, cb) { 383 | try { 384 | js.push(JSON.stringify(data)); 385 | cb(); 386 | } catch (er) { 387 | cb(er); 388 | } 389 | }; 390 | 391 | // anything except null/undefined is fine. 392 | // those are "magic" in the stream API, because they signal EOF. 393 | var objects = [ 394 | { foo: 'bar' }, 395 | 100, 396 | "string", 397 | { nested: { things: [ { foo: 'bar' }, 100, "string" ] } } 398 | ]; 399 | 400 | var ended = false; 401 | js.on('end', function() { 402 | ended = true; 403 | }); 404 | 405 | objects.forEach(function(obj) { 406 | js.write(obj); 407 | var res = js.read(); 408 | t.equal(res, JSON.stringify(obj)); 409 | }); 410 | 411 | js.end(); 412 | 413 | timers.setImmediate(function() { 414 | t.ok(ended); 415 | t.end(); 416 | }) 417 | }); 418 | -------------------------------------------------------------------------------- /builtin/_stream_writable.js: -------------------------------------------------------------------------------- 1 | // Copyright Joyent, Inc. and other Node contributors. 2 | // 3 | // Permission is hereby granted, free of charge, to any person obtaining a 4 | // copy of this software and associated documentation files (the 5 | // "Software"), to deal in the Software without restriction, including 6 | // without limitation the rights to use, copy, modify, merge, publish, 7 | // distribute, sublicense, and/or sell copies of the Software, and to permit 8 | // persons to whom the Software is furnished to do so, subject to the 9 | // following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included 12 | // in all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 17 | // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 20 | // USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | // A bit simpler than readable streams. 23 | // Implement an async ._write(chunk, cb), and it'll handle all 24 | // the drain event emission and buffering. 25 | 26 | module.exports = Writable; 27 | Writable.WritableState = WritableState; 28 | 29 | var util = require('util'); 30 | var Stream = require('stream'); 31 | var timers = require('timers'); 32 | var Buffer = require('buffer').Buffer; 33 | 34 | util.inherits(Writable, Stream); 35 | 36 | function WriteReq(chunk, encoding, cb) { 37 | this.chunk = chunk; 38 | this.encoding = encoding; 39 | this.callback = cb; 40 | } 41 | 42 | function WritableState(options, stream) { 43 | options = options || {}; 44 | 45 | // the point at which write() starts returning false 46 | // Note: 0 is a valid value, means that we always return false if 47 | // the entire buffer is not flushed immediately on write() 48 | var hwm = options.highWaterMark; 49 | this.highWaterMark = (hwm || hwm === 0) ? hwm : 16 * 1024; 50 | 51 | // object stream flag to indicate whether or not this stream 52 | // contains buffers or objects. 53 | this.objectMode = !!options.objectMode; 54 | 55 | // cast to ints. 56 | this.highWaterMark = ~~this.highWaterMark; 57 | 58 | this.needDrain = false; 59 | // at the start of calling end() 60 | this.ending = false; 61 | // when end() has been called, and returned 62 | this.ended = false; 63 | // when 'finish' is emitted 64 | this.finished = false; 65 | 66 | // should we decode strings into buffers before passing to _write? 67 | // this is here so that some node-core streams can optimize string 68 | // handling at a lower level. 69 | var noDecode = options.decodeStrings === false; 70 | this.decodeStrings = !noDecode; 71 | 72 | // Crypto is kind of old and crusty. Historically, its default string 73 | // encoding is 'binary' so we have to make this configurable. 74 | // Everything else in the universe uses 'utf8', though. 75 | this.defaultEncoding = options.defaultEncoding || 'utf8'; 76 | 77 | // not an actual buffer we keep track of, but a measurement 78 | // of how much we're waiting to get pushed to some underlying 79 | // socket or file. 80 | this.length = 0; 81 | 82 | // a flag to see when we're in the middle of a write. 83 | this.writing = false; 84 | 85 | // a flag to be able to tell if the onwrite cb is called immediately, 86 | // or on a later tick. We set this to true at first, becuase any 87 | // actions that shouldn't happen until "later" should generally also 88 | // not happen before the first write call. 89 | this.sync = true; 90 | 91 | // a flag to know if we're processing previously buffered items, which 92 | // may call the _write() callback in the same tick, so that we don't 93 | // end up in an overlapped onwrite situation. 94 | this.bufferProcessing = false; 95 | 96 | // the callback that's passed to _write(chunk,cb) 97 | this.onwrite = function(er) { 98 | onwrite(stream, er); 99 | }; 100 | 101 | // the callback that the user supplies to write(chunk,encoding,cb) 102 | this.writecb = null; 103 | 104 | // the amount that is being written when _write is called. 105 | this.writelen = 0; 106 | 107 | this.buffer = []; 108 | } 109 | 110 | function Writable(options) { 111 | // Writable ctor is applied to Duplexes, though they're not 112 | // instanceof Writable, they're instanceof Readable. 113 | if (!(this instanceof Writable) && !(this instanceof Stream.Duplex)) 114 | return new Writable(options); 115 | 116 | this._writableState = new WritableState(options, this); 117 | 118 | // legacy. 119 | this.writable = true; 120 | 121 | Stream.call(this); 122 | } 123 | 124 | // Otherwise people can pipe Writable streams, which is just wrong. 125 | Writable.prototype.pipe = function() { 126 | this.emit('error', new Error('Cannot pipe. Not readable.')); 127 | }; 128 | 129 | 130 | function writeAfterEnd(stream, state, cb) { 131 | var er = new Error('write after end'); 132 | // TODO: defer error events consistently everywhere, not just the cb 133 | stream.emit('error', er); 134 | timers.setImmediate(function() { 135 | cb(er); 136 | }); 137 | } 138 | 139 | // If we get something that is not a buffer, string, null, or undefined, 140 | // and we're not in objectMode, then that's an error. 141 | // Otherwise stream chunks are all considered to be of length=1, and the 142 | // watermarks determine how many objects to keep in the buffer, rather than 143 | // how many bytes or characters. 144 | function validChunk(stream, state, chunk, cb) { 145 | var valid = true; 146 | if (!Buffer.isBuffer(chunk) && 147 | 'string' !== typeof chunk && 148 | chunk !== null && 149 | chunk !== undefined && 150 | !state.objectMode) { 151 | var er = new TypeError('Invalid non-string/buffer chunk'); 152 | stream.emit('error', er); 153 | timers.setImmediate(function() { 154 | cb(er); 155 | }); 156 | valid = false; 157 | } 158 | return valid; 159 | } 160 | 161 | Writable.prototype.write = function(chunk, encoding, cb) { 162 | var state = this._writableState; 163 | var ret = false; 164 | 165 | if (typeof encoding === 'function') { 166 | cb = encoding; 167 | encoding = null; 168 | } 169 | 170 | if (Buffer.isBuffer(chunk)) 171 | encoding = 'buffer'; 172 | else if (!encoding) 173 | encoding = state.defaultEncoding; 174 | 175 | if (typeof cb !== 'function') 176 | cb = function() {}; 177 | 178 | if (state.ended) 179 | writeAfterEnd(this, state, cb); 180 | else if (validChunk(this, state, chunk, cb)) 181 | ret = writeOrBuffer(this, state, chunk, encoding, cb); 182 | 183 | return ret; 184 | }; 185 | 186 | function decodeChunk(state, chunk, encoding) { 187 | if (!state.objectMode && 188 | state.decodeStrings !== false && 189 | typeof chunk === 'string') { 190 | chunk = new Buffer(chunk, encoding); 191 | } 192 | return chunk; 193 | } 194 | 195 | // if we're already writing something, then just put this 196 | // in the queue, and wait our turn. Otherwise, call _write 197 | // If we return false, then we need a drain event, so set that flag. 198 | function writeOrBuffer(stream, state, chunk, encoding, cb) { 199 | chunk = decodeChunk(state, chunk, encoding); 200 | var len = state.objectMode ? 1 : chunk.length; 201 | 202 | state.length += len; 203 | 204 | var ret = state.length < state.highWaterMark; 205 | state.needDrain = !ret; 206 | 207 | if (state.writing) 208 | state.buffer.push(new WriteReq(chunk, encoding, cb)); 209 | else 210 | doWrite(stream, state, len, chunk, encoding, cb); 211 | 212 | return ret; 213 | } 214 | 215 | function doWrite(stream, state, len, chunk, encoding, cb) { 216 | state.writelen = len; 217 | state.writecb = cb; 218 | state.writing = true; 219 | state.sync = true; 220 | stream._write(chunk, encoding, state.onwrite); 221 | state.sync = false; 222 | } 223 | 224 | function onwriteError(stream, state, sync, er, cb) { 225 | if (sync) 226 | timers.setImmediate(function() { 227 | cb(er); 228 | }); 229 | else 230 | cb(er); 231 | 232 | stream.emit('error', er); 233 | } 234 | 235 | function onwriteStateUpdate(state) { 236 | state.writing = false; 237 | state.writecb = null; 238 | state.length -= state.writelen; 239 | state.writelen = 0; 240 | } 241 | 242 | function onwrite(stream, er) { 243 | var state = stream._writableState; 244 | var sync = state.sync; 245 | var cb = state.writecb; 246 | 247 | onwriteStateUpdate(state); 248 | 249 | if (er) 250 | onwriteError(stream, state, sync, er, cb); 251 | else { 252 | // Check if we're actually ready to finish, but don't emit yet 253 | var finished = needFinish(stream, state); 254 | 255 | if (!finished && !state.bufferProcessing && state.buffer.length) 256 | clearBuffer(stream, state); 257 | 258 | if (sync) { 259 | timers.setImmediate(function() { 260 | afterWrite(stream, state, finished, cb); 261 | }); 262 | } else { 263 | afterWrite(stream, state, finished, cb); 264 | } 265 | } 266 | } 267 | 268 | function afterWrite(stream, state, finished, cb) { 269 | if (!finished) 270 | onwriteDrain(stream, state); 271 | cb(); 272 | if (finished) 273 | finishMaybe(stream, state); 274 | } 275 | 276 | // Must force callback to be called on nextTick, so that we don't 277 | // emit 'drain' before the write() consumer gets the 'false' return 278 | // value, and has a chance to attach a 'drain' listener. 279 | function onwriteDrain(stream, state) { 280 | if (state.length === 0 && state.needDrain) { 281 | state.needDrain = false; 282 | stream.emit('drain'); 283 | } 284 | } 285 | 286 | 287 | // if there's something in the buffer waiting, then process it 288 | function clearBuffer(stream, state) { 289 | state.bufferProcessing = true; 290 | 291 | for (var c = 0; c < state.buffer.length; c++) { 292 | var entry = state.buffer[c]; 293 | var chunk = entry.chunk; 294 | var encoding = entry.encoding; 295 | var cb = entry.callback; 296 | var len = state.objectMode ? 1 : chunk.length; 297 | 298 | doWrite(stream, state, len, chunk, encoding, cb); 299 | 300 | // if we didn't call the onwrite immediately, then 301 | // it means that we need to wait until it does. 302 | // also, that means that the chunk and cb are currently 303 | // being processed, so move the buffer counter past them. 304 | if (state.writing) { 305 | c++; 306 | break; 307 | } 308 | } 309 | 310 | state.bufferProcessing = false; 311 | if (c < state.buffer.length) 312 | state.buffer = state.buffer.slice(c); 313 | else 314 | state.buffer.length = 0; 315 | } 316 | 317 | Writable.prototype._write = function(chunk, encoding, cb) { 318 | cb(new Error('not implemented')); 319 | }; 320 | 321 | Writable.prototype.end = function(chunk, encoding, cb) { 322 | var state = this._writableState; 323 | 324 | if (typeof chunk === 'function') { 325 | cb = chunk; 326 | chunk = null; 327 | encoding = null; 328 | } else if (typeof encoding === 'function') { 329 | cb = encoding; 330 | encoding = null; 331 | } 332 | 333 | if (typeof chunk !== 'undefined' && chunk !== null) 334 | this.write(chunk, encoding); 335 | 336 | // ignore unnecessary end() calls. 337 | if (!state.ending && !state.finished) 338 | endWritable(this, state, cb); 339 | }; 340 | 341 | 342 | function needFinish(stream, state) { 343 | return (state.ending && 344 | state.length === 0 && 345 | !state.finished && 346 | !state.writing); 347 | } 348 | 349 | function finishMaybe(stream, state) { 350 | var need = needFinish(stream, state); 351 | if (need) { 352 | state.finished = true; 353 | stream.emit('finish'); 354 | } 355 | return need; 356 | } 357 | 358 | function endWritable(stream, state, cb) { 359 | state.ending = true; 360 | finishMaybe(stream, state); 361 | if (cb) { 362 | if (state.finished) 363 | timers.setImmediate(cb); 364 | else 365 | stream.once('finish', cb); 366 | } 367 | state.ended = true; 368 | } 369 | --------------------------------------------------------------------------------