├── .gitignore ├── .travis.yml ├── examples └── example.js ├── package.json ├── LICENSE ├── readme.md ├── streamify.js └── test └── test.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: "node_js" 2 | node_js: 3 | - 0.6 4 | - 0.8 5 | - 0.10 6 | notifications: 7 | email: false 8 | -------------------------------------------------------------------------------- /examples/example.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert') 2 | , streamify = require('../streamify').streamify 3 | , streamingWrite = require('../streamify').streamingWrite 4 | , fs = require('fs') 5 | , object = { a: 1, b: 2, c: 3} 6 | 7 | var str = ''; 8 | streamify(object, function(data) { str += data; }); 9 | console.log(str); 10 | // => {"a":1,"b":2,"c":3} 11 | 12 | var str = ''; 13 | streamingWrite('./ACOOLFILE.txt', object, function(data) { str += data; }); 14 | console.log(fs.readFileSync('./ACOOLFILE')); 15 | // => {"a":1,"b":2,"c":3} 16 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "json-streamify", 3 | "description": "Streaming version of `JSON.stringify`", 4 | "version": "0.1.3", 5 | "homepage": "https://github.com/DTrejo/json-streamify", 6 | "repository": { 7 | "type": "git", 8 | "url": "git://github.com/DTrejo/json-streamify.git" 9 | }, 10 | "author": "David Trejo (http://dtrejo.com/)", 11 | "maintainers": [ 12 | "David Trejo (http://dtrejo.com/)" 13 | ], 14 | "main": "streamify.js", 15 | "scripts": { 16 | "test": "nodeunit test/test.js" 17 | }, 18 | "dependencies": { 19 | "traverse": ">=0.2.6" 20 | }, 21 | "devDependencies": { 22 | "nodeunit": ">=0.6.2" 23 | }, 24 | "engines": { 25 | "node": "0.6.x" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2011 David Trejo. All rights reserved. 2 | Permission is hereby granted, free of charge, to any person obtaining a copy 3 | of this software and associated documentation files (the "Software"), to 4 | deal in the Software without restriction, including without limitation the 5 | rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 6 | sell copies of the Software, and to permit persons to whom the Software is 7 | furnished to do so, subject to the following conditions: 8 | 9 | The above copyright notice and this permission notice shall be included in 10 | all copies or substantial portions of the Software. 11 | 12 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 14 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 15 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 16 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 17 | FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 18 | IN THE SOFTWARE. 19 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # JSON Streamify 2 | 3 | [![Build Status](https://travis-ci.org/DTrejo/json-streamify.png)](http://travis-ci.org/DTrejo/json-streamify) 4 | 5 | A streaming version of `JSON.stringify`. 6 | 7 | npm install json-streamify 8 | 9 | ## Methods 10 | 11 | ### `streamify(object, function)` 12 | 13 | Passes the function chunks of the object until there is none of the object left. 14 | `streamify` is a synchronous function. 15 | 16 | var assert = require('assert') 17 | , streamify = require('../streamify').streamify 18 | , streamingWrite = require('../streamify').streamingWrite 19 | , fs = require('fs') 20 | , object = { a: 1, b: 2, c: 3} 21 | 22 | var str = ''; 23 | streamify(object, function(data) { str += data; }); 24 | console.log(str); 25 | // => {"a":1,"b":2,"c":3} 26 | 27 | ### `streamingWrite(filepath, object, callback)` 28 | 29 | Writes chunks of the object to the given filepath until there is none of the object left. 30 | When it finishes, it calls `callback`. 31 | 32 | var str = ''; 33 | streamingWrite('./ACOOLFILE.txt', object, function(data) { str += data; }, function() { 34 | 35 | console.log(fs.readFileSync('./ACOOLFILE')); 36 | // => {"a":1,"b":2,"c":3} 37 | }); 38 | 39 | Most of this was written by [James Halliday](http://substack.net), with a few small things by [David Trejo](http://dtrejo.com/). 40 | 41 | ### TODOs 42 | 43 | - allow a stream to be passed into `streamify(object, stream)`? 44 | -------------------------------------------------------------------------------- /streamify.js: -------------------------------------------------------------------------------- 1 | // 2 | // Pretty much all written by James Halliday (substack.net) 3 | // Small bits by David Trejo (dtrejo.com) 4 | // 5 | var Traverse = require('traverse') 6 | , fs = require('fs') 7 | ; 8 | 9 | // emit is a function 10 | // also, this is a sync function 11 | exports.streamify = function streamify(obj, emit) { 12 | 13 | Traverse(obj).forEach(function to_s (node) { 14 | if (Array.isArray(node)) { 15 | this.before(function () { emit('['); }); 16 | this.post(function (child) { 17 | if (!child.isLast) emit(','); 18 | }); 19 | this.after(function () { emit(']'); }); 20 | 21 | } else if (typeof node == 'object') { 22 | this.before(function () { emit('{'); }); 23 | this.pre(function (x, key) { 24 | to_s(key); 25 | emit(':'); 26 | }); 27 | this.post(function (child) { 28 | if (!child.isLast) emit(','); 29 | }); 30 | this.after(function () { emit('}'); }); 31 | 32 | } else if (typeof node == 'string') { 33 | emit(JSON.stringify(node)); 34 | 35 | } else if (typeof node == 'function') { 36 | emit('null'); 37 | 38 | } else if (node.toString) { 39 | emit(node.toString()); 40 | 41 | } else { 42 | emit(node); 43 | } 44 | }); 45 | }; 46 | 47 | exports.streamingWrite = function streamingWrite(path, object, cb) { 48 | 49 | var stream = fs.createWriteStream(path, { flags: 'w+', encoding: 'utf8' }); 50 | 51 | if (cb) { 52 | stream.on('close', cb); 53 | stream.on('error', cb); 54 | } 55 | 56 | exports.streamify(object, function(chunk) { 57 | stream.write(chunk); 58 | }); 59 | 60 | // all writes have been sent, b/c streamify is a sync function. 61 | stream.end(); 62 | 63 | }; 64 | -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert') 2 | , streamify = require('../streamify').streamify 3 | , streamingWrite = require('../streamify').streamingWrite 4 | , testCase = require('nodeunit').testCase 5 | , fs = require('fs') 6 | , small = { a: 1, b: 2, c: 3 } 7 | , medium = {"J":{"I":0.18181818181818182,"bought":0.18181818181818182,"some":0.18181818181818182,"bread":0.09090909090909091,"butter":0.09090909090909091},"'ai":{"I":0.18181818181818182,"bought":0.18181818181818182,"some":0.18181818181818182,"bread":0.09090909090909091,"butter":0.09090909090909091},"acheter":{"I":0.18181818181818182,"bought":0.18181818181818182,"some":0.18181818181818182,"bread":0.09090909090909091,"butter":0.09090909090909091},"du":{"I":0.18181818181818182,"bought":0.18181818181818182,"some":0.18181818181818182,"bread":0.09090909090909091,"butter":0.09090909090909091},"pain":{"I":0.09999999999999999,"bought":0.09999999999999999,"some":0.09999999999999999,"bread":0.18333333333333332,"We":0.08333333333333333,"must":0.08333333333333333,"eat":0.08333333333333333,"the":0.08333333333333333,"white":0.08333333333333333},"beurre":{"I":0.25,"bought":0.25,"some":0.25,"butter":0.25},"Nous":{"We":0.16666666666666669,"must":0.16666666666666669,"eat":0.16666666666666669,"the":0.16666666666666669,"white":0.16666666666666669,"bread":0.16666666666666669},"devon":{"We":0.16666666666666669,"must":0.16666666666666669,"eat":0.16666666666666669,"the":0.16666666666666669,"white":0.16666666666666669,"bread":0.16666666666666669},"manger":{"We":0.16666666666666669,"must":0.16666666666666669,"eat":0.16666666666666669,"the":0.16666666666666669,"white":0.16666666666666669,"bread":0.16666666666666669},"le":{"We":0.16666666666666669,"must":0.16666666666666669,"eat":0.16666666666666669,"the":0.16666666666666669,"white":0.16666666666666669,"bread":0.16666666666666669},"blanc":{"We":0.16666666666666669,"must":0.16666666666666669,"eat":0.16666666666666669,"the":0.16666666666666669,"white":0.16666666666666669,"bread":0.16666666666666669}} 8 | , size = 100 9 | , big = [] 10 | ; 11 | 12 | while(size--) { 13 | big.push(medium); 14 | } 15 | 16 | module.exports = testCase({ 17 | test_small_object: function(assert) { 18 | var str = ''; 19 | streamify(small, function(data) { str += data; }); 20 | 21 | assert.equals(JSON.stringify(small), str 22 | , 'JSON.stringify and streamify return the same string for a small object'); 23 | assert.done(); 24 | } 25 | , test_big_object: function(assert) { 26 | var str = ''; 27 | streamify(big, function(data) { str += data; }); 28 | 29 | assert.equals(JSON.stringify(big), str 30 | , 'JSON.stringify and streamify return the same string for a big object'); 31 | assert.done(); 32 | } 33 | , test_small_streaming_write: function(assert) { 34 | path = './DELETEME.txt'; 35 | streamingWrite(path, small, function() { 36 | assert.equals(JSON.stringify(small), fs.readFileSync(path).toString('utf8') 37 | , 'Streaming write to file with small object returns same as JSON.stringify'); 38 | fs.unlinkSync(path); 39 | assert.done(); 40 | }); 41 | } 42 | , test_big_streaming_write: function(assert) { 43 | path = './DELETEME.txt'; 44 | streamingWrite(path, big, function() { 45 | assert.equals(JSON.stringify(big), fs.readFileSync(path).toString('utf8') 46 | , 'Streaming write to file with big object returns same as JSON.stringify'); 47 | fs.unlinkSync(path); 48 | assert.done(); 49 | }); 50 | } 51 | , test_encode_object: function(assert) { 52 | var s = ''; 53 | for (var i = 0; i < 255; i++) { s += String.fromCharCode(i); } 54 | var obj = { "a tricky string": s }; 55 | var str = ''; 56 | streamify(obj, function(data) { str += data; }); 57 | 58 | assert.equals(JSON.stringify(obj), str 59 | , 'Properly escapes strings'); 60 | 61 | assert.equals(JSON.parse(JSON.stringify(obj)) + '', JSON.parse(str) + '' 62 | , 'Properly parses strings'); 63 | 64 | assert.done(); 65 | } 66 | }); --------------------------------------------------------------------------------