[Pkg-javascript-commits] [node-jstream] 01/02: Imported Upstream version 0.2.7

Andrew Kelley andrewrk-guest at moszumanska.debian.org
Thu Jul 3 22:36:11 UTC 2014


This is an automated email from the git hooks/post-receive script.

andrewrk-guest pushed a commit to branch master
in repository node-jstream.

commit de834459512a1cbcbf80730864e7fbb1957862ef
Author: Andrew Kelley <superjoe30 at gmail.com>
Date:   Thu Jul 3 22:31:21 2014 +0000

    Imported Upstream version 0.2.7
---
 .gitignore                |   1 +
 .travis.yml               |   4 ++
 LICENSE                   |  19 +++++
 README.md                 |  54 ++++++++++++++
 lib/index.js              | 176 ++++++++++++++++++++++++++++++++++++++++++++++
 package.json              |  29 ++++++++
 test/assets/array.json    |   6 ++
 test/assets/arrayKey.json |   6 ++
 test/assets/data.json     |  19 +++++
 test/assets/function.json |  14 ++++
 test/assets/many.json     |  18 +++++
 test/assets/propName.json |   7 ++
 test/assets/regexp.json   |   7 ++
 test/main-test.js         |  31 ++++++++
 test/path-test.js         |  45 ++++++++++++
 test/run.js               |  35 +++++++++
 16 files changed, 471 insertions(+)

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..3c3629e
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+node_modules
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..09d3ef3
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,4 @@
+language: node_js
+node_js:
+  - 0.8
+  - 0.10
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..809ab08
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,19 @@
+Copyright (C) 2012 by Roly Fentanes
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE. 
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..e34476b
--- /dev/null
+++ b/README.md
@@ -0,0 +1,54 @@
+# node-jstream [![Build Status](https://secure.travis-ci.org/fent/node-jstream.png)](http://travis-ci.org/fent/node-jstream)
+
+Continuously reads in JSON and outputs Javascript objects. Meant to be used with keep-alive connections that send back JSON on updates.
+
+# Usage
+
+```js
+var JStream = require('jstream');
+var request = require('request');
+
+request('http://api.myhost.com/updates.json')
+  .pipe(new JStream()).on('data', function(obj) {
+    console.log('new js object');
+    console.log(obj);
+  });
+```
+
+# API
+### new JStream([path])
+Creates an instance of JStream. Inherits from `Stream`. Can be written to and emits `data` events with Javascript objects.
+
+`path` can be an array of property names, `RegExp`'s, booleans, and/or functions. Objects that match will be emitted in `data` events. Passing no `path` means emitting whole Javascript objects as they come in. For example, given the `path` `['results', true, 'name']` and the following JSON gets written into JStream
+
+```js
+{ "results": [
+  {"seq":99230
+  ,"id":"newsemitter"
+  ,"changes":[{"rev":"5-aca7782ab6beeaef30c36b888f817d2e"}]}
+, {"seq":99235
+  ,"id":"chain-tiny"
+  ,"changes":[{"rev":"19-82224279a743d2744f10d52697cdaea9"}]}
+, {"seq":99238
+  ,"id":"Hanzi"
+  ,"changes":[{"rev":"4-5ed20f975bd563ae5d1c8c1d574fe24c"}],"deleted":true}
+] }
+```
+
+JStream will emit `newsemitter`, `chain-tiny`, and `Hanzi` in its `data` event.
+
+
+# Install
+
+    npm install jstream
+
+
+# Tests
+Tests are written with [mocha](http://visionmedia.github.com/mocha/)
+
+```bash
+npm test
+```
+
+# License
+MIT
diff --git a/lib/index.js b/lib/index.js
new file mode 100644
index 0000000..f3eb480
--- /dev/null
+++ b/lib/index.js
@@ -0,0 +1,176 @@
+var Transform = require('readable-stream').Transform;
+var util      = require('util');
+var clarinet  = require('clarinet');
+
+
+/**
+ * @constructor
+ * @extends {Transform}
+ */
+var JStream = module.exports = function(path) {
+  Transform.call(this, { objectMode: true });
+
+  var parser = this.parser = new clarinet.createStream()
+    , self = this
+    , stack = []
+    , currObj = {}
+    , currKey = 'root'
+    , inArray
+    , pathMatch = true
+    , parentPathMatch = true
+    , comparator
+    ;
+
+  if (path) {
+    // add some listeners only if path is given
+    var onvaluepath = function onvaluepath(value) {
+      if (pathMatch && stack.length === path.length &&
+          match(currKey, comparator)) {
+        self.push(value);
+      }
+    };
+
+    var onopenpath = function onopenpath() {
+      if (stack.length) {
+        parentPathMatch = pathMatch = parentPathMatch &&
+          comparator !== undefined &&
+          match(currKey, comparator);
+      }
+
+      comparator = path[stack.length];
+    };
+
+    parser.on('value', onvaluepath);
+    parser.on('openobject', onopenpath);
+    parser.on('openarray', onopenpath);
+  }
+
+
+  parser.on('value', function onvalue(value) {
+    currObj[currKey] = value;
+    if (inArray) {
+      currKey++;
+    }
+  });
+
+  parser.on('key', function onkey(key) {
+    currKey = key;
+  });
+  
+  function onopen(key) {
+    var obj, openArray;
+
+    if (key === undefined) {
+      // openarray
+      obj = currObj[currKey] = [];
+      openArray = true;
+      key = 0;
+
+    } else {
+      // openobject
+      obj = currObj[currKey] = {};
+      openArray = false;
+    }
+
+    stack.push({
+      obj: currObj
+    , key: currKey + (inArray ? 1 : '')
+    , arr: inArray
+    , path: pathMatch
+    });
+
+    currObj = obj;
+    currKey = key;
+    inArray = openArray;
+  }
+
+  function onclose() {
+    var current = stack.pop();
+    currObj     = current.obj;
+    currKey     = current.key;
+    inArray     = current.arr;
+    parentPathMatch = stack.length ? stack[stack.length - 1].path : true;
+  }
+
+  parser.on('openobject', onopen);
+  parser.on('closeobject', onclose);
+  parser.on('openarray', onopen);
+  parser.on('closearray', onclose);
+
+  parser.on('error', function onerror(err) {
+    self.readable = false;
+    self.writable = false;
+    parser.emit = function() {};
+    self.emit('error', err);
+  });
+
+  parser.on('end', self.push.bind(self, null));
+
+  if (path) {
+    var onclosepath = function onclosepath() {
+      if (pathMatch && stack.length === path.length) {
+        self.push(currObj[currKey]);
+      }
+      comparator = path[stack.length - 1];
+    };
+
+    parser.on('closeobject', onclosepath);
+    parser.on('closearray', onclosepath);
+
+  } else {
+    // if `path` is not given, emit `data` event whenever a full
+    // objectd on the root is parsed
+    parser.on('closeobject', function onobjectavailable() {
+      if (!stack.length || stack.length === 1 && inArray) {
+        var key = inArray ? currKey - 1 : currKey;
+        self.push(currObj[key]);
+      }
+    });
+  }
+
+};
+util.inherits(JStream, Transform);
+
+
+/**
+ * Writes to the parser.
+ *
+ * @param {Buffer|String} chunk
+ * @param {String} encoding
+ * @param {Function(!Error)} callback
+ */
+JStream.prototype._transform = function(chunk, encoding, callback) {
+  this.parser.write(chunk);
+  callback(null);
+};
+
+
+/**
+ * Compare a key against a string, number, RegExp, boolean, or function.
+ *
+ * @param {String} key
+ * @param {String|Number|RegExp|Boolean|Function} comparator
+ * @return {Boolean}
+ */
+function match(key, comparator) {
+  switch (typeof comparator) {
+    case 'string':
+    case 'number':
+      return key === comparator;
+
+    case 'boolean':
+      return comparator;
+
+    case 'function':
+      return comparator(key);
+
+    case 'object':
+      if (comparator instanceof RegExp) {
+        return comparator.test(key);
+      }
+      break;
+
+  }
+
+  throw new TypeError('Path object not supported.');
+}
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..a6cacfb
--- /dev/null
+++ b/package.json
@@ -0,0 +1,29 @@
+{
+  "name": "jstream",
+  "description": "Continously reads in JSON and outputs Javascript objects.",
+  "keywords": ["stream", "json", "parse", "api"],
+  "version": "0.2.7",
+  "repository": {
+    "type": "git",
+    "url": "git://github.com/fent/node-jstream.git"
+  },
+  "author": "Roly Fentanes (https://github.com/fent)",
+  "main": "./lib/index.js",
+  "scripts": {
+    "test": "mocha -R spec --ignore-leaks test/*-test.js"
+  },
+  "directories": {
+    "lib": "./lib"
+  },
+  "dependencies": {
+    "clarinet": "~0.8.1",
+    "readable-stream": "~1.1.9"
+  },
+  "devDependencies": {
+    "mocha": "*"
+  },
+  "licenses": [ {
+    "type": "MIT",
+    "url" : "http://github.com/fent/node-jstream/raw/master/LICENSE"
+  }]
+}
diff --git a/test/assets/array.json b/test/assets/array.json
new file mode 100644
index 0000000..f781cf5
--- /dev/null
+++ b/test/assets/array.json
@@ -0,0 +1,6 @@
+[
+  { "id": "one" },
+  { "id": "two" },
+  { "id": "three" },
+  { "id": "four" }
+]
diff --git a/test/assets/arrayKey.json b/test/assets/arrayKey.json
new file mode 100644
index 0000000..61d190b
--- /dev/null
+++ b/test/assets/arrayKey.json
@@ -0,0 +1,6 @@
+{ "results": [
+  [42, 74, 83, 2]
+, [11, 6, 5, 74]
+, [92, 7, 64, 12]
+, ["hi", "there", "grandma", 4]
+] }
diff --git a/test/assets/data.json b/test/assets/data.json
new file mode 100644
index 0000000..6b49255
--- /dev/null
+++ b/test/assets/data.json
@@ -0,0 +1,19 @@
+{ "hello": "world" }
+{ "0": "a"
+, "1": "b"
+, "2": "c" }
+
+
+{
+
+    "list": ["mr", "plow"]}
+
+{ "foo": [
+    "bar"
+  , "baz"
+  , 2
+  , { "one": "two" }
+  , ["a", "b", "c"]
+  ]
+, "yes": "no"
+}
diff --git a/test/assets/function.json b/test/assets/function.json
new file mode 100644
index 0000000..452510d
--- /dev/null
+++ b/test/assets/function.json
@@ -0,0 +1,14 @@
+{ "statusCode": "200"
+, "same": { "helo": "dawg" }
+, "results": [42, { "more": "results" }, 23]
+, "a": { "b": 2 }
+, "c": []
+, "something": "long"
+}
+{ "statusCode": "200"
+, "same": { "helo": "dawg" }
+, "results": [42, { "more": "results" }, 23]
+, "a": { "b": 2 }
+, "c": []
+, "something": "long"
+}
diff --git a/test/assets/many.json b/test/assets/many.json
new file mode 100644
index 0000000..2db3c60
--- /dev/null
+++ b/test/assets/many.json
@@ -0,0 +1,18 @@
+{"total_rows":129,"offset":0,"rows":[
+  { "id":"change1_0.6995461115147918"
+  , "key":"change1_0.6995461115147918"
+  , "value":{"rev":"1-e240bae28c7bb3667f02760f6398d508"}
+  , "doc":{
+      "_id":  "change1_0.6995461115147918"
+    , "_rev": "1-e240bae28c7bb3667f02760f6398d508","hello":1}
+  },
+  { "id":"change2_0.6995461115147918"
+  , "key":"change2_0.6995461115147918"
+  , "value":{"rev":"1-13677d36b98c0c075145bb8975105153"}
+  , "doc":{
+      "_id":"change2_0.6995461115147918"
+    , "_rev":"1-13677d36b98c0c075145bb8975105153"
+    , "hello":2
+    }
+  }
+]}
diff --git a/test/assets/propName.json b/test/assets/propName.json
new file mode 100644
index 0000000..b008adf
--- /dev/null
+++ b/test/assets/propName.json
@@ -0,0 +1,7 @@
+{ "date": "today"
+, "name": "foo"
+, "value": "hi there" }
+
+{ "date": "tomorrow"
+, "name": "bar"
+, "value": "hello world"}
diff --git a/test/assets/regexp.json b/test/assets/regexp.json
new file mode 100644
index 0000000..0286816
--- /dev/null
+++ b/test/assets/regexp.json
@@ -0,0 +1,7 @@
+{ "name": "energy sword"
+, "type": "melee"
+, "color": "white"
+, "_attack": 500
+, "_cooldown": 2000
+, "_lunge": true
+}
diff --git a/test/main-test.js b/test/main-test.js
new file mode 100644
index 0000000..5409fe1
--- /dev/null
+++ b/test/main-test.js
@@ -0,0 +1,31 @@
+var run  = require('./run');
+var path = require('path');
+
+
+/*jshint quotmark:false */
+var file1 = path.join(__dirname, 'assets', 'data.json');
+var expected1 = [
+  { "hello": "world" }
+, { "0": "a", "1": "b", "2": "c" }
+, { "list": ["mr", "plow"] }
+, { "foo": [
+      "bar"
+    , "baz"
+    , 2
+    , { "one": "two" }
+    , ["a", "b", "c"]
+    ]
+  , "yes": "no"
+  }
+];
+
+var file2 = path.join(__dirname, 'assets', 'array.json');
+var expected2 = [
+  { "id": "one" }
+, { "id": "two" }
+, { "id": "three" }
+, { "id": "four" }
+];
+
+run('Read a file with JSON strings', file1, expected1);
+run('Read a file with JSON objects in an array', file2, expected2);
diff --git a/test/path-test.js b/test/path-test.js
new file mode 100644
index 0000000..8539395
--- /dev/null
+++ b/test/path-test.js
@@ -0,0 +1,45 @@
+var run  = require('./run');
+var path = require('path');
+
+
+/*jshint quotmark:false */
+var file1 = path.join(__dirname, 'assets', 'propName.json');
+var expected1 = ['foo', 'bar'];
+
+var file2 = path.join(__dirname, 'assets', 'arrayKey.json');
+var expected2 = [83, 5, 64, 'grandma'];
+
+var file3 = path.join(__dirname, 'assets', 'regexp.json');
+var expected3 = [500, 2000, true];
+
+var file4 = path.join(__dirname, 'assets', 'function.json');
+var expected4 = [
+  "200"
+,  [42, { "more": "results" }, 23]
+, "long"
+, "200"
+,  [42, { "more": "results" }, 23]
+, "long"
+];
+
+var file5 = path.join(__dirname, 'assets', 'many.json');
+var expected5 = [
+  { "_id":  "change1_0.6995461115147918"
+  , "_rev": "1-e240bae28c7bb3667f02760f6398d508"
+  , "hello": 1 }
+, { "_id":"change2_0.6995461115147918"
+  , "_rev":"1-13677d36b98c0c075145bb8975105153"
+  , "hello": 2 }
+];
+
+
+describe('Parse JSON with a path that contains', function() {
+  run('a property name', file1, expected1, ['name']);
+  run('a boolean and array key', file2, expected2, [true, true, 2]);
+  run('a RegExp', file3, expected3, [/^_/]);
+  run('a function', file4, expected4, [function(key) {
+    return key.length > 5;
+  }]);
+
+  run('many of the above', file5, expected5, ['rows', true, 'doc']);
+});
diff --git a/test/run.js b/test/run.js
new file mode 100644
index 0000000..8ffbdd0
--- /dev/null
+++ b/test/run.js
@@ -0,0 +1,35 @@
+var JStream = require('..');
+var assert  = require('assert');
+var fs      = require('fs');
+
+
+/**
+ * Tests that a `file` emits `expected` results given a `path`
+ *
+ * @param (string) description
+ * @param (string) file
+ * @param (Array.Object) expected
+ * @param (Array.Object) path
+ */
+module.exports = function runTest(description, file, expected, path) {
+  describe(description, function() {
+    it('JStream emits expected Javascript objects', function(done) {
+      var rs = fs.createReadStream(file);
+      var jstream = new JStream(path);
+      rs.pipe(jstream);
+
+      var dataEmitted = false;
+      var n = 0;
+
+      jstream.on('data', function(obj) {
+        dataEmitted = true;
+        assert.deepEqual(obj, expected[n++]);
+      });
+
+      jstream.on('end', function() {
+        assert.ok(dataEmitted);
+        done();
+      });
+    });
+  });
+};

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-javascript/node-jstream.git



More information about the Pkg-javascript-commits mailing list