From 48d3064733145f579c57d50ff51157074eb2d50c Mon Sep 17 00:00:00 2001 From: Juan Caicedo Date: Sun, 24 Jan 2016 10:37:10 -0500 Subject: [PATCH 01/11] add contributing doc --- CONTRIBUTING.md | 50 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) create mode 100644 CONTRIBUTING.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..5b661349 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,50 @@ +# Contributing to Oboe.js + +:+1::tada: First off, thanks for taking the time to contribute! :tada::+1: + +The following is a set of guidelines for contributing to Oboe.js. These are just guidelines, not rules, use your best judgment and feel free to propose changes to this document in a pull request. + +## Read the docs :) + +Oboe.js has some [awesome documentation](http://oboejs.com/) explaining how and why to use the library. + +## Questions/Help + +Sometimes your question can be addressed by reading the [API](http://oboejs.com/api) closely. It's short and nicely organized! + +Please post questions to [StackOverflow](http://stackoverflow.com/) using the `javascript` tag and mention Oboe.js in the title. + +If you file an issue with a question, it will be closed. We're not trying to be mean, it just helps keep the issues tab cleaner so we can keep improving the library. + +## Reporting Bugs / Requesting Features + +If you've found an issue, please submit it in [the issues](https://github.com/jimhigson/oboe.js/issues). A link to a [jsbin](https://jsbin.com/)/[codepen](http://codepen.io/)/[plunkr](https://plnkr.co/) that demonstrates the issue if it's on the client, or a github repo if it's on the server, greatly increases our ability to help. + +## Pull Requests + +If you would like to add functionality, please submit [an issue](https://github.com/jimhigson/oboe.js/issues) +first to make sure it's a direction we want to take. + +Please do the following: +* Follow the existing styles +* Create an example for that demonstrates your changes so people can see how your changes work + +In your PR description include any information that will help a maintainer understand and test your changes. The easier it is to read and run your PR, the faster it can get merged! + +#### Notes + +- Please don't commit any changes to the `dist/` directory. This is only committed for releases. + +### What does Oboe need help with? + +#### An oboe.js StackOverflow tag + +If you have enough [reputation on StackOverflow](http://stackoverflow.com/help/whats-reputation) to make a tag for `oboe.js`, please do that for us! That will help us keep track of questions being asked on there and respond to them faster. + +#### Helping others! + +There is a [Google Group](https://groups.google.com/forum/#!forum/oboejs) for general project discussion. If you have a moment to help other people using the library, please stop in. + +#### Contributing to community + +- Write examples! The website has a [section](http://oboejs.com/examples) showing common use-cases, and it could always use some more. Feel free to submit a PR to [the website](https://github.com/jimhigson/oboe.js-website). We would also like to showcase applications using Oboe, so if you've published one and want to share it, file it [in the website issues](https://github.com/jimhigson/oboe.js-website/issues) and we'll showcase it! From 38a25c1937fe7b3d283e614782822b6f1fded78f Mon Sep 17 00:00:00 2001 From: charlierudolph Date: Sun, 24 Jan 2016 17:55:58 -0800 Subject: [PATCH 02/11] dont catch errors thrown in callbacks --- dist/oboe-browser.js | 183 +++++----- dist/oboe-browser.min.js | 2 +- dist/oboe-node.js | 183 +++++----- src/instanceApi.js | 181 +++++---- test/specs/instanceApi.unit.spec.js | 532 +++++++++++++-------------- test/specs/oboe.component.spec.js | 476 ++++++++++++------------ test/specs/oboe.integration.spec.js | 549 ++++++++++++++-------------- 7 files changed, 1046 insertions(+), 1060 deletions(-) diff --git a/dist/oboe-browser.js b/dist/oboe-browser.js index 67481b45..a05072de 100644 --- a/dist/oboe-browser.js +++ b/dist/oboe-browser.js @@ -4,7 +4,7 @@ // having a local undefined, window, Object etc allows slightly better minification: (function (window, Object, Array, Error, JSON, undefined ) { - // v2.1.1-1-gb70a959 + // v2.1.2-2-g8cc8edc /* @@ -2294,10 +2294,10 @@ function patternAdapter(oboeBus, jsonPathCompiler) { } -/** +/** * The instance API is the thing that is returned when oboe() is called. * it allows: - * + * * - listeners for various events to be added and removed * - the http response header/headers to be read */ @@ -2310,77 +2310,77 @@ function instanceApi(oboeBus, contentSource){ emitNodeSwap = oboeBus(NODE_SWAP).emit, /** - * Add any kind of listener that the instance api exposes - */ + * Add any kind of listener that the instance api exposes + */ addListener = varArgs(function( eventId, parameters ){ - + if( oboeApi[eventId] ) { - - // for events added as .on(event, callback), if there is a + + // for events added as .on(event, callback), if there is a // .event() equivalent with special behaviour , pass through - // to that: - apply(parameters, oboeApi[eventId]); + // to that: + apply(parameters, oboeApi[eventId]); } else { - + // we have a standard Node.js EventEmitter 2-argument call. // The first parameter is the listener. var event = oboeBus(eventId), listener = parameters[0]; - + if( fullyQualifiedNamePattern.test(eventId) ) { - - // allow fully-qualified node/path listeners - // to be added - addForgettableCallback(event, listener); + + // allow fully-qualified node/path listeners + // to be added + addForgettableCallback(event, listener); } else { - - // the event has no special handling, pass through - // directly onto the event bus: + + // the event has no special handling, pass through + // directly onto the event bus: event.on( listener); } } - + return oboeApi; // chaining }), - + /** - * Remove any kind of listener that the instance api exposes - */ + * Remove any kind of listener that the instance api exposes + */ removeListener = function( eventId, p2, p3 ){ - + if( eventId == 'done' ) { - + rootNodeFinishedEvent.un(p2); - + } else if( eventId == 'node' || eventId == 'path' ) { - - // allow removal of node and path - oboeBus.un(eventId + ':' + p2, p3); + + // allow removal of node and path + oboeBus.un(eventId + ':' + p2, p3); } else { - + // we have a standard Node.js EventEmitter 2-argument call. // The second parameter is the listener. This may be a call // to remove a fully-qualified node/path listener but requires // no special handling var listener = p2; - oboeBus(eventId).un(listener); + oboeBus(eventId).un(listener); } - - return oboeApi; // chaining - }; - - /** + + return oboeApi; // chaining + }; + + /** * Add a callback, wrapped in a try/catch so as to not break the - * execution of Oboe if an exception is thrown (fail events are + * execution of Oboe if an exception is thrown (fail events are * fired instead) - * + * * The callback is used as the listener id so that it can later be * removed using .un(callback) */ function addProtectedCallback(eventName, callback) { oboeBus(eventName).on(protectedCallback(callback), callback); - return oboeApi; // chaining + return oboeApi; // chaining } /** @@ -2388,55 +2388,55 @@ function instanceApi(oboeBus, contentSource){ * execution, the callback will be de-registered */ function addForgettableCallback(event, callback, listenerId) { - + // listenerId is optional and if not given, the original // callback will be used listenerId = listenerId || callback; - + var safeCallback = protectedCallback(callback); - + event.on( function() { - + var discard = false; - + oboeApi.forget = function(){ discard = true; - }; - - apply( arguments, safeCallback ); - + }; + + apply( arguments, safeCallback ); + delete oboeApi.forget; - + if( discard ) { event.un(listenerId); } }, listenerId); - - return oboeApi; // chaining + + return oboeApi; // chaining } - - /** + + /** * wrap a callback so that if it throws, Oboe.js doesn't crash but instead - * handles it like a normal error + * throw the error in another event loop */ function protectedCallback( callback ) { return function() { - try{ - return callback.apply(oboeApi, arguments); + try{ + return callback.apply(oboeApi, arguments); }catch(e) { - - // An error occured during the callback, publish it on the event bus - oboeBus(FAIL_EVENT).emit( errorReport(undefined, undefined, e)); - } - } + setTimeout(function() { + throw e; + }); + } + } } /** * Return the fully qualified event for when a pattern matches * either a node or a path - * + * * @param type {String} either 'node' or 'path' - */ + */ function fullyQualifiedPatternMatchEvent(type, pattern) { return oboeBus(type + ':' + pattern); } @@ -2446,7 +2446,7 @@ function instanceApi(oboeBus, contentSource){ var returnValueFromCallback = callback.apply(this, arguments); if( defined(returnValueFromCallback) ) { - + if( returnValueFromCallback == oboe.drop ) { emitNodeDrop(); } else { @@ -2465,7 +2465,7 @@ function instanceApi(oboeBus, contentSource){ } else { effectiveCallback = callback; } - + addForgettableCallback( fullyQualifiedPatternMatchEvent(eventId, pattern), effectiveCallback, @@ -2477,32 +2477,32 @@ function instanceApi(oboeBus, contentSource){ * Add several listeners at a time, from a map */ function addMultipleNodeOrPathListeners(eventId, listenerMap) { - + for( var pattern in listenerMap ) { addSingleNodeOrPathListener(eventId, pattern, listenerMap[pattern]); } - } - + } + /** * implementation behind .onPath() and .onNode() - */ + */ function addNodeOrPathListenerApi( eventId, jsonPathOrListenerMap, callback ){ - + if( isString(jsonPathOrListenerMap) ) { addSingleNodeOrPathListener(eventId, jsonPathOrListenerMap, callback); } else { addMultipleNodeOrPathListeners(eventId, jsonPathOrListenerMap); } - + return oboeApi; // chaining } - - + + // some interface methods are only filled in after we receive - // values and are noops before that: + // values and are noops before that: oboeBus(ROOT_PATH_FOUND).on( function(rootNode) { - oboeApi.root = functor(rootNode); + oboeApi.root = functor(rootNode); }); /** @@ -2510,45 +2510,44 @@ function instanceApi(oboeBus, contentSource){ * instance API */ oboeBus(HTTP_START).on( function(_statusCode, headers) { - + oboeApi.header = function(name) { - return name ? headers[name] + return name ? headers[name] : headers ; } }); - + /** - * Construct and return the public API of the Oboe instance to be + * Construct and return the public API of the Oboe instance to be * returned to the calling application - */ + */ return oboeApi = { on : addListener, - addListener : addListener, + addListener : addListener, removeListener : removeListener, - emit : oboeBus.emit, - + emit : oboeBus.emit, + node : partialComplete(addNodeOrPathListenerApi, 'node'), path : partialComplete(addNodeOrPathListenerApi, 'path'), - - done : partialComplete(addForgettableCallback, rootNodeFinishedEvent), + + done : partialComplete(addForgettableCallback, rootNodeFinishedEvent), start : partialComplete(addProtectedCallback, HTTP_START ), - - // fail doesn't use protectedCallback because + + // fail doesn't use protectedCallback because // could lead to non-terminating loops fail : oboeBus(FAIL_EVENT).on, - + // public api calling abort fires the ABORTING event abort : oboeBus(ABORTING).emit, - + // initially return nothing for header and root header : noop, root : noop, - + source : contentSource - }; + }; } - /** * This file sits just behind the API which is used to attain a new diff --git a/dist/oboe-browser.min.js b/dist/oboe-browser.min.js index 6d8dd72f..3a414c4f 100644 --- a/dist/oboe-browser.min.js +++ b/dist/oboe-browser.min.js @@ -1 +1 @@ -!function(a,b,c,d,e,f){function g(a,b){return function(){return a.call(this,b.apply(this,arguments))}}function h(a){return function(b){return b[a]}}function i(a,b){return b.apply(f,a)}function j(a){var b=a.length-1,d=c.prototype.slice;if(0==b)return function(){return a.call(this,d.call(arguments))};if(1==b)return function(){return a.call(this,arguments[0],d.call(arguments,1))};var e=c(a.length);return function(){for(var c=0;b>c;c++)e[c]=arguments[c];return e[b]=d.call(arguments,b),a.apply(this,e)}}function k(a){return function(b,c){return a(c,b)}}function l(a,b){return function(c){return a(c)&&b(c)}}function m(){}function n(){return!0}function o(a){return function(){return a}}function p(a,b){return b&&b.constructor===a}function q(a){return a!==f}function r(a,c){return c instanceof b&&y(function(a){return a in c},a)}function s(a,b){return[a,b]}function t(a){return A(a.reduce(k(s),X))}function u(a){return w(function(a,b){return a.unshift(b),a},[],a)}function v(a,b){return b?s(a(Y(b)),v(a,Z(b))):X}function w(a,b,c){return c?a(w(a,b,Z(c)),Y(c)):b}function x(a,b,c){function d(a,c){return a?b(Y(a))?(c(Y(a)),Z(a)):s(Y(a),d(Z(a),c)):X}return d(a,c||m)}function y(a,b){return!b||a(Y(b))&&y(a,Z(b))}function z(a,b){a&&(Y(a).apply(null,b),z(Z(a),b))}function A(a){function b(a,c){return a?b(Z(a),s(Y(a),c)):c}return b(a,X)}function B(a,b){return b&&(a(Y(b))?Y(b):B(a,Z(b)))}function C(a){"use strict";function b(){var a=0;P.length>p&&(c("Max buffer length exceeded: textNode"),a=Math.max(a,P.length)),Q.length>p&&(c("Max buffer length exceeded: numberNode"),a=Math.max(a,Q.length)),O=p-a+Y}function c(a){P&&(m(P),n(),P=""),i=d(a+"\nLn: "+$+"\nCol: "+Z+"\nChr: "+j),o(N(f,f,i))}function e(){return T==s?(m({}),n(),void(S=!0)):((T!==t||0!==X)&&c("Unexpected end"),P&&(m(P),n(),P=""),void(S=!0))}function g(a){return"\r"==a||"\n"==a||" "==a||" "==a}function h(a){if(!i){if(S)return c("Cannot write after close");var d=0;for(j=a[0];j&&(k=j,j=a[d++]);)switch(Y++,"\n"==j?($++,Z=0):Z++,T){case s:if("{"===j)T=u;else if("["===j)T=w;else if(!g(j))return c("Non-whitespace before {[.");continue;case z:case u:if(g(j))continue;if(T===z)U.push(A);else{if("}"===j){m({}),n(),T=U.pop()||t;continue}U.push(v)}if('"'!==j)return c('Malformed object key should start with " ');T=y;continue;case A:case v:if(g(j))continue;if(":"===j)T===v?(U.push(v),P&&(m({}),l(P),P=""),X++):P&&(l(P),P=""),T=t;else if("}"===j)P&&(m(P),n(),P=""),n(),X--,T=U.pop()||t;else{if(","!==j)return c("Bad object");T===v&&U.push(v),P&&(m(P),n(),P=""),T=z}continue;case w:case t:if(g(j))continue;if(T===w){if(m([]),X++,T=t,"]"===j){n(),X--,T=U.pop()||t;continue}U.push(x)}if('"'===j)T=y;else if("{"===j)T=u;else if("["===j)T=w;else if("t"===j)T=B;else if("f"===j)T=E;else if("n"===j)T=I;else if("-"===j)Q+=j;else if("0"===j)Q+=j,T=M;else{if(-1==="123456789".indexOf(j))return c("Bad value");Q+=j,T=M}continue;case x:if(","===j)U.push(x),P&&(m(P),n(),P=""),T=t;else{if("]"!==j){if(g(j))continue;return c("Bad array")}P&&(m(P),n(),P=""),n(),X--,T=U.pop()||t}continue;case y:var e=d-1;a:for(;;){for(;W>0;)if(V+=j,j=a.charAt(d++),4===W?(P+=String.fromCharCode(parseInt(V,16)),W=0,e=d-1):W++,!j)break a;if('"'===j&&!R){T=U.pop()||t,P+=a.substring(e,d-1),P||(m(""),n());break}if("\\"===j&&!R&&(R=!0,P+=a.substring(e,d-1),j=a.charAt(d++),!j))break;if(R){if(R=!1,"n"===j?P+="\n":"r"===j?P+="\r":"t"===j?P+=" ":"f"===j?P+="\f":"b"===j?P+="\b":"u"===j?(W=1,V=""):P+=j,j=a.charAt(d++),e=d-1,j)continue;break}q.lastIndex=d;var f=q.exec(a);if(!f){d=a.length+1,P+=a.substring(e,d-1);break}if(d=f.index+1,j=a.charAt(f.index),!j){P+=a.substring(e,d-1);break}}continue;case B:if(!j)continue;if("r"!==j)return c("Invalid true started with t"+j);T=C;continue;case C:if(!j)continue;if("u"!==j)return c("Invalid true started with tr"+j);T=D;continue;case D:if(!j)continue;if("e"!==j)return c("Invalid true started with tru"+j);m(!0),n(),T=U.pop()||t;continue;case E:if(!j)continue;if("a"!==j)return c("Invalid false started with f"+j);T=F;continue;case F:if(!j)continue;if("l"!==j)return c("Invalid false started with fa"+j);T=G;continue;case G:if(!j)continue;if("s"!==j)return c("Invalid false started with fal"+j);T=H;continue;case H:if(!j)continue;if("e"!==j)return c("Invalid false started with fals"+j);m(!1),n(),T=U.pop()||t;continue;case I:if(!j)continue;if("u"!==j)return c("Invalid null started with n"+j);T=J;continue;case J:if(!j)continue;if("l"!==j)return c("Invalid null started with nu"+j);T=K;continue;case K:if(!j)continue;if("l"!==j)return c("Invalid null started with nul"+j);m(null),n(),T=U.pop()||t;continue;case L:if("."!==j)return c("Leading zero not followed by .");Q+=j,T=M;continue;case M:if(-1!=="0123456789".indexOf(j))Q+=j;else if("."===j){if(-1!==Q.indexOf("."))return c("Invalid number has two dots");Q+=j}else if("e"===j||"E"===j){if(-1!==Q.indexOf("e")||-1!==Q.indexOf("E"))return c("Invalid number has two exponential");Q+=j}else if("+"===j||"-"===j){if("e"!==k&&"E"!==k)return c("Invalid symbol in number");Q+=j}else Q&&(m(parseFloat(Q)),n(),Q=""),d--,T=U.pop()||t;continue;default:return c("Unknown state: "+T)}Y>=O&&b()}}var i,j,k,l=a(qb).emit,m=a(rb).emit,n=a(sb).emit,o=a(jb).emit,p=65536,q=/[\\"\n]/g,r=0,s=r++,t=r++,u=r++,v=r++,w=r++,x=r++,y=r++,z=r++,A=r++,B=r++,C=r++,D=r++,E=r++,F=r++,G=r++,H=r++,I=r++,J=r++,K=r++,L=r++,M=r,O=p,P="",Q="",R=!1,S=!1,T=s,U=[],V=null,W=0,X=0,Y=0,Z=0,$=1;a(nb).on(h),a(ob).on(e)}function D(a,b){"use strict";function c(a){return function(b){d=a(d,b)}}var d,e={};for(var f in b)a(f).on(c(b[f]),e);a(hb).on(function(a){var b,c=Y(d),e=ab(c),f=Z(d);f&&(b=bb(Y(f)),b[e]=a)}),a(ib).on(function(){var a,b=Y(d),c=ab(b),e=Z(d);e&&(a=bb(Y(e)),delete a[c])}),a(pb).on(function(){for(var c in b)a(c).un(e)})}function E(a){var b={};return a&&a.split("\r\n").forEach(function(a){var c=a.indexOf(": ");b[a.substring(0,c)]=a.substring(c+2)}),b}function F(a,b){function c(a){return{"http:":80,"https:":443}[a]}function d(b){return b.port||c(b.protocol||a.protocol)}return!!(b.protocol&&b.protocol!=a.protocol||b.host&&b.host!=a.host||b.host&&d(b)!=d(a))}function G(a){var b=/(\w+:)?(?:\/\/)([\w.-]+)?(?::(\d+))?\/?/,c=b.exec(a)||[];return{protocol:c[1]||"",host:c[2]||"",port:c[3]||""}}function H(){return new XMLHttpRequest}function I(b,c,d,e,g,h,i){"use strict";function j(){var a=c.responseText,b=a.substr(m);b&&k(b),m=V(a)}var k=b(nb).emit,l=b(jb).emit,m=0,n=!0;b(pb).on(function(){c.onreadystatechange=null,c.abort()}),"onprogress"in c&&(c.onprogress=j),c.onreadystatechange=function(){function a(){try{n&&b(mb).emit(c.status,E(c.getAllResponseHeaders())),n=!1}catch(a){}}switch(c.readyState){case 2:case 3:return a();case 4:a();var d=2==String(c.status)[0];d?(j(),b(ob).emit()):l(N(c.status,c.responseText))}};try{c.open(d,e,!0);for(var o in h)c.setRequestHeader(o,h[o]);F(a.location,G(e))||c.setRequestHeader("X-Requested-With","XMLHttpRequest"),c.withCredentials=i,c.send(g)}catch(p){a.setTimeout(T(l,N(f,f,p)),0)}}function J(a,b){return{key:a,node:b}}function K(a){function b(a,b){var d=bb(Y(a));return p(c,d)?f(a,V(d),b):a}function d(a,c){if(!a)return j(c),f(a,cb,c);var d=b(a,c),g=Z(d),h=ab(Y(d));return e(g,h,c),s(J(h,c),g)}function e(a,b,c){bb(Y(a))[b]=c}function f(a,b,c){a&&e(a,b,c);var d=s(J(b,c),a);return h(d),d}function g(a){return i(a),Z(a)||k(bb(Y(a)))}var h=a(fb).emit,i=a(gb).emit,j=a(lb).emit,k=a(kb).emit,l={};return l[rb]=d,l[sb]=g,l[qb]=f,l}function L(a,b,c){function d(a){return function(b){return b.id==a}}var e,f;return{on:function(c,d){var g={listener:c,id:d||c};return b&&b.emit(a,c,g.id),e=s(g,e),f=s(c,f),this},emit:function(){z(f,arguments)},un:function(b){var g;e=x(e,d(b),function(a){g=a}),g&&(f=x(f,function(a){return a==g.listener}),c&&c.emit(a,g.listener,g.id))},listeners:function(){return f},hasListener:function(a){var b=a?d(a):n;return q(B(b,e))}}}function M(){function a(a){return c[a]=L(a,d,e)}function b(b){return c[b]||a(b)}var c={},d=a("newListener"),e=a("removeListener");return["emit","on","un"].forEach(function(a){b[a]=j(function(c,d){i(d,b(c)[a])})}),b}function N(a,b,c){try{var d=e.parse(b)}catch(f){}return{statusCode:a,body:b,jsonBody:d,thrown:c}}function O(a,b){function c(a,b,c){var d=A(c);a(b,u(Z(v(ab,d))),u(v(bb,d)))}function d(b,d,e){var f=a(b).emit;d.on(function(a){var b=e(a);b!==!1&&c(f,bb(b),a)},b),a("removeListener").on(function(c){c==b&&(a(c).listeners()||d.un(b))})}var e={node:a(gb),path:a(fb)};a("newListener").on(function(a){var c=/(node|path):(.*)/.exec(a);if(c){var f=e[c[1]];f.hasListener(a)||d(a,f,b(c[2]))}})}function P(a,b){function c(b,c){return a(b).on(e(c),c),p}function d(a,b,c){c=c||b;var d=e(b);return a.on(function(){var b=!1;p.forget=function(){b=!0},i(arguments,d),delete p.forget,b&&a.un(c)},c),p}function e(b){return function(){try{return b.apply(p,arguments)}catch(c){a(jb).emit(N(f,f,c))}}}function g(b,c){return a(b+":"+c)}function h(a){return function(){var b=a.apply(this,arguments);q(b)&&(b==S.drop?t():u(b))}}function k(a,b,c){var e;e="node"==a?h(c):c,d(g(a,b),e,c)}function l(a,b){for(var c in b)k(a,c,b[c])}function n(a,b,c){return W(b)?k(a,b,c):l(a,b),p}var p,r=/^(node|path):./,s=a(kb),t=a(ib).emit,u=a(hb).emit,v=j(function(b,c){if(p[b])i(c,p[b]);else{var e=a(b),f=c[0];r.test(b)?d(e,f):e.on(f)}return p}),w=function(b,c,d){if("done"==b)s.un(c);else if("node"==b||"path"==b)a.un(b+":"+c,d);else{var e=c;a(b).un(e)}return p};return a(lb).on(function(a){p.root=o(a)}),a(mb).on(function(a,b){p.header=function(a){return a?b[a]:b}}),p={on:v,addListener:v,removeListener:w,emit:a.emit,node:T(n,"node"),path:T(n,"path"),done:T(d,s),start:T(c,mb),fail:a(jb).on,abort:a(pb).emit,header:m,root:m,source:b}}function Q(a,b,c,d,e){var f=M();return b&&I(f,H(),a,b,c,d,e),C(f),D(f,K(f)),O(f,db),P(f,b)}function R(a,b,c,d,f,g,h){function i(a,b){return b===!1&&(a+=-1==a.indexOf("?")?"?":"&",a+="_="+(new Date).getTime()),a}return f=f?e.parse(e.stringify(f)):{},d?W(d)||(d=e.stringify(d),f["Content-Type"]=f["Content-Type"]||"application/json"):d=null,a(c||"GET",i(b,h),d,f,g||!1)}function S(a){var b=$("resume","pause","pipe"),c=T(r,b);return a?c(a)||W(a)?R(Q,a):R(Q,a.url,a.method,a.body,a.headers,a.withCredentials,a.cached):Q()}var T=j(function(a,b){var c=b.length;return j(function(d){for(var e=0;ec;c++)e[c]=arguments[c];return e[b]=d.call(arguments,b),a.apply(this,e)}}function k(a){return function(b,c){return a(c,b)}}function l(a,b){return function(c){return a(c)&&b(c)}}function m(){}function n(){return!0}function o(a){return function(){return a}}function p(a,b){return b&&b.constructor===a}function q(a){return a!==f}function r(a,c){return c instanceof b&&y(function(a){return a in c},a)}function s(a,b){return[a,b]}function t(a){return A(a.reduce(k(s),X))}function u(a){return w(function(a,b){return a.unshift(b),a},[],a)}function v(a,b){return b?s(a(Y(b)),v(a,Z(b))):X}function w(a,b,c){return c?a(w(a,b,Z(c)),Y(c)):b}function x(a,b,c){function d(a,c){return a?b(Y(a))?(c(Y(a)),Z(a)):s(Y(a),d(Z(a),c)):X}return d(a,c||m)}function y(a,b){return!b||a(Y(b))&&y(a,Z(b))}function z(a,b){a&&(Y(a).apply(null,b),z(Z(a),b))}function A(a){function b(a,c){return a?b(Z(a),s(Y(a),c)):c}return b(a,X)}function B(a,b){return b&&(a(Y(b))?Y(b):B(a,Z(b)))}function C(a){"use strict";function b(){var a=0;P.length>p&&(c("Max buffer length exceeded: textNode"),a=Math.max(a,P.length)),Q.length>p&&(c("Max buffer length exceeded: numberNode"),a=Math.max(a,Q.length)),O=p-a+Y}function c(a){P&&(m(P),n(),P=""),i=d(a+"\nLn: "+$+"\nCol: "+Z+"\nChr: "+j),o(N(f,f,i))}function e(){return T==s?(m({}),n(),void(S=!0)):((T!==t||0!==X)&&c("Unexpected end"),P&&(m(P),n(),P=""),void(S=!0))}function g(a){return"\r"==a||"\n"==a||" "==a||" "==a}function h(a){if(!i){if(S)return c("Cannot write after close");var d=0;for(j=a[0];j&&(k=j,j=a[d++]);)switch(Y++,"\n"==j?($++,Z=0):Z++,T){case s:if("{"===j)T=u;else if("["===j)T=w;else if(!g(j))return c("Non-whitespace before {[.");continue;case z:case u:if(g(j))continue;if(T===z)U.push(A);else{if("}"===j){m({}),n(),T=U.pop()||t;continue}U.push(v)}if('"'!==j)return c('Malformed object key should start with " ');T=y;continue;case A:case v:if(g(j))continue;if(":"===j)T===v?(U.push(v),P&&(m({}),l(P),P=""),X++):P&&(l(P),P=""),T=t;else if("}"===j)P&&(m(P),n(),P=""),n(),X--,T=U.pop()||t;else{if(","!==j)return c("Bad object");T===v&&U.push(v),P&&(m(P),n(),P=""),T=z}continue;case w:case t:if(g(j))continue;if(T===w){if(m([]),X++,T=t,"]"===j){n(),X--,T=U.pop()||t;continue}U.push(x)}if('"'===j)T=y;else if("{"===j)T=u;else if("["===j)T=w;else if("t"===j)T=B;else if("f"===j)T=E;else if("n"===j)T=I;else if("-"===j)Q+=j;else if("0"===j)Q+=j,T=M;else{if(-1==="123456789".indexOf(j))return c("Bad value");Q+=j,T=M}continue;case x:if(","===j)U.push(x),P&&(m(P),n(),P=""),T=t;else{if("]"!==j){if(g(j))continue;return c("Bad array")}P&&(m(P),n(),P=""),n(),X--,T=U.pop()||t}continue;case y:var e=d-1;a:for(;;){for(;W>0;)if(V+=j,j=a.charAt(d++),4===W?(P+=String.fromCharCode(parseInt(V,16)),W=0,e=d-1):W++,!j)break a;if('"'===j&&!R){T=U.pop()||t,P+=a.substring(e,d-1),P||(m(""),n());break}if("\\"===j&&!R&&(R=!0,P+=a.substring(e,d-1),j=a.charAt(d++),!j))break;if(R){if(R=!1,"n"===j?P+="\n":"r"===j?P+="\r":"t"===j?P+=" ":"f"===j?P+="\f":"b"===j?P+="\b":"u"===j?(W=1,V=""):P+=j,j=a.charAt(d++),e=d-1,j)continue;break}q.lastIndex=d;var f=q.exec(a);if(!f){d=a.length+1,P+=a.substring(e,d-1);break}if(d=f.index+1,j=a.charAt(f.index),!j){P+=a.substring(e,d-1);break}}continue;case B:if(!j)continue;if("r"!==j)return c("Invalid true started with t"+j);T=C;continue;case C:if(!j)continue;if("u"!==j)return c("Invalid true started with tr"+j);T=D;continue;case D:if(!j)continue;if("e"!==j)return c("Invalid true started with tru"+j);m(!0),n(),T=U.pop()||t;continue;case E:if(!j)continue;if("a"!==j)return c("Invalid false started with f"+j);T=F;continue;case F:if(!j)continue;if("l"!==j)return c("Invalid false started with fa"+j);T=G;continue;case G:if(!j)continue;if("s"!==j)return c("Invalid false started with fal"+j);T=H;continue;case H:if(!j)continue;if("e"!==j)return c("Invalid false started with fals"+j);m(!1),n(),T=U.pop()||t;continue;case I:if(!j)continue;if("u"!==j)return c("Invalid null started with n"+j);T=J;continue;case J:if(!j)continue;if("l"!==j)return c("Invalid null started with nu"+j);T=K;continue;case K:if(!j)continue;if("l"!==j)return c("Invalid null started with nul"+j);m(null),n(),T=U.pop()||t;continue;case L:if("."!==j)return c("Leading zero not followed by .");Q+=j,T=M;continue;case M:if(-1!=="0123456789".indexOf(j))Q+=j;else if("."===j){if(-1!==Q.indexOf("."))return c("Invalid number has two dots");Q+=j}else if("e"===j||"E"===j){if(-1!==Q.indexOf("e")||-1!==Q.indexOf("E"))return c("Invalid number has two exponential");Q+=j}else if("+"===j||"-"===j){if("e"!==k&&"E"!==k)return c("Invalid symbol in number");Q+=j}else Q&&(m(parseFloat(Q)),n(),Q=""),d--,T=U.pop()||t;continue;default:return c("Unknown state: "+T)}Y>=O&&b()}}var i,j,k,l=a(qa).emit,m=a(ra).emit,n=a(sa).emit,o=a(ja).emit,p=65536,q=/[\\"\n]/g,r=0,s=r++,t=r++,u=r++,v=r++,w=r++,x=r++,y=r++,z=r++,A=r++,B=r++,C=r++,D=r++,E=r++,F=r++,G=r++,H=r++,I=r++,J=r++,K=r++,L=r++,M=r,O=p,P="",Q="",R=!1,S=!1,T=s,U=[],V=null,W=0,X=0,Y=0,Z=0,$=1;a(na).on(h),a(oa).on(e)}function D(a,b){"use strict";function c(a){return function(b){d=a(d,b)}}var d,e={};for(var f in b)a(f).on(c(b[f]),e);a(ha).on(function(a){var b,c=Y(d),e=aa(c),f=Z(d);f&&(b=ba(Y(f)),b[e]=a)}),a(ia).on(function(){var a,b=Y(d),c=aa(b),e=Z(d);e&&(a=ba(Y(e)),delete a[c])}),a(pa).on(function(){for(var c in b)a(c).un(e)})}function E(a){var b={};return a&&a.split("\r\n").forEach(function(a){var c=a.indexOf(": ");b[a.substring(0,c)]=a.substring(c+2)}),b}function F(a,b){function c(a){return{"http:":80,"https:":443}[a]}function d(b){return b.port||c(b.protocol||a.protocol)}return!!(b.protocol&&b.protocol!=a.protocol||b.host&&b.host!=a.host||b.host&&d(b)!=d(a))}function G(a){var b=/(\w+:)?(?:\/\/)([\w.-]+)?(?::(\d+))?\/?/,c=b.exec(a)||[];return{protocol:c[1]||"",host:c[2]||"",port:c[3]||""}}function H(){return new XMLHttpRequest}function I(b,c,d,e,g,h,i){"use strict";function j(){var a=c.responseText,b=a.substr(m);b&&k(b),m=V(a)}var k=b(na).emit,l=b(ja).emit,m=0,n=!0;b(pa).on(function(){c.onreadystatechange=null,c.abort()}),"onprogress"in c&&(c.onprogress=j),c.onreadystatechange=function(){function a(){try{n&&b(ma).emit(c.status,E(c.getAllResponseHeaders())),n=!1}catch(a){}}switch(c.readyState){case 2:case 3:return a();case 4:a();var d=2==String(c.status)[0];d?(j(),b(oa).emit()):l(N(c.status,c.responseText))}};try{c.open(d,e,!0);for(var o in h)c.setRequestHeader(o,h[o]);F(a.location,G(e))||c.setRequestHeader("X-Requested-With","XMLHttpRequest"),c.withCredentials=i,c.send(g)}catch(p){a.setTimeout(T(l,N(f,f,p)),0)}}function J(a,b){return{key:a,node:b}}function K(a){function b(a,b){var d=ba(Y(a));return p(c,d)?f(a,V(d),b):a}function d(a,c){if(!a)return j(c),f(a,ca,c);var d=b(a,c),g=Z(d),h=aa(Y(d));return e(g,h,c),s(J(h,c),g)}function e(a,b,c){ba(Y(a))[b]=c}function f(a,b,c){a&&e(a,b,c);var d=s(J(b,c),a);return h(d),d}function g(a){return i(a),Z(a)||k(ba(Y(a)))}var h=a(fa).emit,i=a(ga).emit,j=a(la).emit,k=a(ka).emit,l={};return l[ra]=d,l[sa]=g,l[qa]=f,l}function L(a,b,c){function d(a){return function(b){return b.id==a}}var e,f;return{on:function(c,d){var g={listener:c,id:d||c};return b&&b.emit(a,c,g.id),e=s(g,e),f=s(c,f),this},emit:function(){z(f,arguments)},un:function(b){var g;e=x(e,d(b),function(a){g=a}),g&&(f=x(f,function(a){return a==g.listener}),c&&c.emit(a,g.listener,g.id))},listeners:function(){return f},hasListener:function(a){var b=a?d(a):n;return q(B(b,e))}}}function M(){function a(a){return c[a]=L(a,d,e)}function b(b){return c[b]||a(b)}var c={},d=a("newListener"),e=a("removeListener");return["emit","on","un"].forEach(function(a){b[a]=j(function(c,d){i(d,b(c)[a])})}),b}function N(a,b,c){try{var d=e.parse(b)}catch(f){}return{statusCode:a,body:b,jsonBody:d,thrown:c}}function O(a,b){function c(a,b,c){var d=A(c);a(b,u(Z(v(aa,d))),u(v(ba,d)))}function d(b,d,e){var f=a(b).emit;d.on(function(a){var b=e(a);b!==!1&&c(f,ba(b),a)},b),a("removeListener").on(function(c){c==b&&(a(c).listeners()||d.un(b))})}var e={node:a(ga),path:a(fa)};a("newListener").on(function(a){var c=/(node|path):(.*)/.exec(a);if(c){var f=e[c[1]];f.hasListener(a)||d(a,f,b(c[2]))}})}function P(a,b){function c(b,c){return a(b).on(e(c),c),n}function d(a,b,c){c=c||b;var d=e(b);return a.on(function(){var b=!1;n.forget=function(){b=!0},i(arguments,d),delete n.forget,b&&a.un(c)},c),n}function e(a){return function(){try{return a.apply(n,arguments)}catch(b){setTimeout(function(){throw b})}}}function f(b,c){return a(b+":"+c)}function g(a){return function(){var b=a.apply(this,arguments);q(b)&&(b==S.drop?s():t(b))}}function h(a,b,c){var e;e="node"==a?g(c):c,d(f(a,b),e,c)}function k(a,b){for(var c in b)h(a,c,b[c])}function l(a,b,c){return W(b)?h(a,b,c):k(a,b),n}var n,p=/^(node|path):./,r=a(ka),s=a(ia).emit,t=a(ha).emit,u=j(function(b,c){if(n[b])i(c,n[b]);else{var e=a(b),f=c[0];p.test(b)?d(e,f):e.on(f)}return n}),v=function(b,c,d){if("done"==b)r.un(c);else if("node"==b||"path"==b)a.un(b+":"+c,d);else{var e=c;a(b).un(e)}return n};return a(la).on(function(a){n.root=o(a)}),a(ma).on(function(a,b){n.header=function(a){return a?b[a]:b}}),n={on:u,addListener:u,removeListener:v,emit:a.emit,node:T(l,"node"),path:T(l,"path"),done:T(d,r),start:T(c,ma),fail:a(ja).on,abort:a(pa).emit,header:m,root:m,source:b}}function Q(a,b,c,d,e){var f=M();return b&&I(f,H(),a,b,c,d,e),C(f),D(f,K(f)),O(f,da),P(f,b)}function R(a,b,c,d,f,g,h){function i(a,b){return b===!1&&(a+=-1==a.indexOf("?")?"?":"&",a+="_="+(new Date).getTime()),a}return f=f?e.parse(e.stringify(f)):{},d?W(d)||(d=e.stringify(d),f["Content-Type"]=f["Content-Type"]||"application/json"):d=null,a(c||"GET",i(b,h),d,f,g||!1)}function S(a){var b=$("resume","pause","pipe"),c=T(r,b);return a?c(a)||W(a)?R(Q,a):R(Q,a.url,a.method,a.body,a.headers,a.withCredentials,a.cached):Q()}var T=j(function(a,b){var c=b.length;return j(function(d){for(var e=0;e (waitStart + waitMs); } } - + var callbackSpy, fullResponse, aborted; - + function abortCallback() { this.abort(); aborted = true; - } - + } + function theRequestToBeAborted() { return aborted - } - + } + function whenDoneFn(obj) { fullResponse = obj; } - + function doneCalled(){ - return !!fullResponse + return !!fullResponse } /** @@ -787,60 +777,57 @@ function contextTypeFrom(header){ return header.split(';')[0]; } - + beforeEach(function () { aborted = false; fullResponse = null; callbackSpy = jasmine.createSpy('callbackSpy'); - + this.addMatchers({ toHaveBeenGivenAnyError:function(){ var errorReport = this.actual.mostRecentCall.args[0], maybeErr = errorReport.thrown; - + if( typeof maybeErr != 'object' ) { return false; - } - - if( maybeErr instanceof Error ) { + } + + if( maybeErr instanceof Error ) { return true; } - + // instanceof Error doesn't always work in Safari (tested v6.0.5) // because: // - // ((new XMLHttpRequestException()) instanceof Error) == false + // ((new XMLHttpRequestException()) instanceof Error) == false if( window && window.XMLHttpRequestException && maybeErr instanceof XMLHttpRequestException ) { return true; } - + // if that didn't work fallback to some duck typing: - return( (typeof maybeErr.message != 'undefined') && + return( (typeof maybeErr.message != 'undefined') && (typeof maybeErr.lineNumber != 'undefined') ); }, toHaveBeenGivenThrowee:function(expectedError){ var errorReport = this.actual.mostRecentCall.args[0]; - + return errorReport.thrown === expectedError; - }, + }, toHaveBeenGivenErrorStatusCode:function(expectedCode){ var errorReport = this.actual.mostRecentCall.args[0]; - - return errorReport.statusCode === expectedCode; + + return errorReport.statusCode === expectedCode; }, toHaveBeenGivenBodyJson:function(expectedBodyJson){ var errorReport = this.actual.mostRecentCall.args[0]; - - return JSON.stringify(expectedBodyJson) - === - JSON.stringify(errorReport.jsonBody); - } - }); - }); - - }); -})(typeof Platform == 'undefined'? require('../libs/platform.js') : Platform) - + return JSON.stringify(expectedBodyJson) + === + JSON.stringify(errorReport.jsonBody); + } + }); + }); + }); +})(typeof Platform == 'undefined'? require('../libs/platform.js') : Platform) From c1ec66db9402ca08050588820111e3981a9a226a Mon Sep 17 00:00:00 2001 From: Juan Caicedo Date: Sat, 20 Feb 2016 11:19:57 -0500 Subject: [PATCH 03/11] change grunt's node-build-run to node-build --- Gruntfile.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gruntfile.js b/Gruntfile.js index ce05b83d..d9ec5448 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -233,7 +233,7 @@ module.exports = function (grunt) { testNode:{ files: FILES_TRIGGERING_KARMA, tasks:[ - 'node-build-run'] + 'node-build'] }, restartStreamSourceAndRunTests:{ From 50861b21365245fc4319e6f963028ff0857670df Mon Sep 17 00:00:00 2001 From: Juan Caicedo Date: Sat, 20 Feb 2016 15:05:53 -0500 Subject: [PATCH 04/11] add index.js for npm link --- index.js | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 index.js diff --git a/index.js b/index.js new file mode 100644 index 00000000..d1cc9476 --- /dev/null +++ b/index.js @@ -0,0 +1,3 @@ +var oboe = require('./dist/oboe-node'); + +module.exports = oboe; From 33d7bc2cad85215444858a0ff0c7004ee8a2cbe7 Mon Sep 17 00:00:00 2001 From: Juan Caicedo Date: Sun, 21 Feb 2016 11:06:26 -0500 Subject: [PATCH 05/11] format contributing doc --- CONTRIBUTING.md | 53 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 36 insertions(+), 17 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5b661349..50f2dc9d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,49 +2,68 @@ :+1::tada: First off, thanks for taking the time to contribute! :tada::+1: -The following is a set of guidelines for contributing to Oboe.js. These are just guidelines, not rules, use your best judgment and feel free to propose changes to this document in a pull request. +The following is a set of guidelines for contributing to Oboe.js. These are +just guidelines, not rules, use your best judgment and feel free to propose +changes to this document in a pull request. ## Read the docs :) -Oboe.js has some [awesome documentation](http://oboejs.com/) explaining how and why to use the library. +Oboe.js has some [awesome documentation](http://oboejs.com/) +explaining how and why to use the library. ## Questions/Help -Sometimes your question can be addressed by reading the [API](http://oboejs.com/api) closely. It's short and nicely organized! +Sometimes your question can be addressed by reading the +[API](http://oboejs.com/api) closely. It's short and nicely organized! -Please post questions to [StackOverflow](http://stackoverflow.com/) using the `javascript` tag and mention Oboe.js in the title. +Please post questions to [StackOverflow](http://stackoverflow.com/) +using the `oboe.js` and`javascript` tags. -If you file an issue with a question, it will be closed. We're not trying to be mean, it just helps keep the issues tab cleaner so we can keep improving the library. +If you file an issue with an implementation question, it will be closed. +We're not trying to be mean, it just helps keep the issues tab cleaner so we can + keep improving the library. ## Reporting Bugs / Requesting Features -If you've found an issue, please submit it in [the issues](https://github.com/jimhigson/oboe.js/issues). A link to a [jsbin](https://jsbin.com/)/[codepen](http://codepen.io/)/[plunkr](https://plnkr.co/) that demonstrates the issue if it's on the client, or a github repo if it's on the server, greatly increases our ability to help. +If you've found an issue, please submit it in +[the issues](https://github.com/jimhigson/oboe.js/issues). A link to a +[jsbin](https://jsbin.com/)/[codepen](http://codepen.io/)/[plunkr](https://plnkr.co/) +that demonstrates the issue (if it's on the client), or a github repo +(if it's on the server), greatly increases our ability to help. ## Pull Requests -If you would like to add functionality, please submit [an issue](https://github.com/jimhigson/oboe.js/issues) -first to make sure it's a direction we want to take. +If you would like to add functionality, please submit +[an issue](https://github.com/jimhigson/oboe.js/issues) first to make sure it's +a direction we want to take. Please do the following: * Follow the existing styles -* Create an example for that demonstrates your changes so people can see how your changes work +* Create an example for that demonstrates your changes so people can see how +your changes work -In your PR description include any information that will help a maintainer understand and test your changes. The easier it is to read and run your PR, the faster it can get merged! - -#### Notes - -- Please don't commit any changes to the `dist/` directory. This is only committed for releases. +In your PR description include any information that will help a maintainer +understand and test your changes. The easier it is to read and run your PR, +the faster it can get merged! ### What does Oboe need help with? #### An oboe.js StackOverflow tag -If you have enough [reputation on StackOverflow](http://stackoverflow.com/help/whats-reputation) to make a tag for `oboe.js`, please do that for us! That will help us keep track of questions being asked on there and respond to them faster. +If you have enough [reputation on StackOverflow](http://stackoverflow.com/help/whats-reputation) +to make a tag for `oboe.js`, please do that for us! That will help us keep track + of questions being asked on there and respond to them faster. #### Helping others! -There is a [Google Group](https://groups.google.com/forum/#!forum/oboejs) for general project discussion. If you have a moment to help other people using the library, please stop in. +There is a [Google Group](https://groups.google.com/forum/#!forum/oboejs) for +general project discussion. If you have a moment to help other people using the +library, please stop in. #### Contributing to community -- Write examples! The website has a [section](http://oboejs.com/examples) showing common use-cases, and it could always use some more. Feel free to submit a PR to [the website](https://github.com/jimhigson/oboe.js-website). We would also like to showcase applications using Oboe, so if you've published one and want to share it, file it [in the website issues](https://github.com/jimhigson/oboe.js-website/issues) and we'll showcase it! +- Write examples! The website has a [section](http://oboejs.com/examples) +showing common use-cases, and it could always use some more. Feel free to submit +a PR to [the website](https://github.com/jimhigson/oboe.js-website). +- We would also like to showcase applications using Oboe, so if you've published +one and want to share it, file it [in the website issues](https://github.com/jimhigson/oboe.js-website/issues) and we'll showcase it! From bdb97d67cff3aa226ad8732cf3fd7aa6b970bb2a Mon Sep 17 00:00:00 2001 From: Juan Caicedo Date: Sun, 21 Feb 2016 11:27:45 -0500 Subject: [PATCH 06/11] add link to bug repo --- CONTRIBUTING.md | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 50f2dc9d..2dae8c9c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -26,7 +26,13 @@ We're not trying to be mean, it just helps keep the issues tab cleaner so we can ## Reporting Bugs / Requesting Features If you've found an issue, please submit it in -[the issues](https://github.com/jimhigson/oboe.js/issues). A link to a +[the issues](https://github.com/jimhigson/oboe.js/issues). + +To increase our ability to help, please: +- If it's a server-side bug, fork our +[bug-template](https://github.com/JuanCaicedo/oboe-bug-template), recreate your +bug, and then provide a link to that repo. +- If it's a client-side template, provide a link to a [jsbin](https://jsbin.com/)/[codepen](http://codepen.io/)/[plunkr](https://plnkr.co/) that demonstrates the issue (if it's on the client), or a github repo (if it's on the server), greatly increases our ability to help. @@ -48,12 +54,6 @@ the faster it can get merged! ### What does Oboe need help with? -#### An oboe.js StackOverflow tag - -If you have enough [reputation on StackOverflow](http://stackoverflow.com/help/whats-reputation) -to make a tag for `oboe.js`, please do that for us! That will help us keep track - of questions being asked on there and respond to them faster. - #### Helping others! There is a [Google Group](https://groups.google.com/forum/#!forum/oboejs) for @@ -66,4 +66,6 @@ library, please stop in. showing common use-cases, and it could always use some more. Feel free to submit a PR to [the website](https://github.com/jimhigson/oboe.js-website). - We would also like to showcase applications using Oboe, so if you've published -one and want to share it, file it [in the website issues](https://github.com/jimhigson/oboe.js-website/issues) and we'll showcase it! +one and want to share it, file it +[in the website issues](https://github.com/jimhigson/oboe.js-website/issues) +and we'll showcase it! From ac1dc94af5e9b84d482d3ede4d4bb135581f8915 Mon Sep 17 00:00:00 2001 From: Tom Kujala Date: Tue, 5 Jul 2016 16:14:24 -0400 Subject: [PATCH 07/11] fix(clarinet): empty keys Fixed a bug in the forked clarinet module where empty keys were not emitting the `SAX_KEY` event and resulting in an error being thrown. The parser now uses `undefined` as the default value for a text node instead of the empty string. --- src/libs/clarinet.js | 44 ++++++++++++++--------------- test/json/emptyKey.json | 4 +++ test/specs/oboe.integration.spec.js | 16 +++++++++++ 3 files changed, 42 insertions(+), 22 deletions(-) create mode 100644 test/json/emptyKey.json diff --git a/src/libs/clarinet.js b/src/libs/clarinet.js index 4bb3e2e1..c67bc830 100644 --- a/src/libs/clarinet.js +++ b/src/libs/clarinet.js @@ -61,7 +61,7 @@ function clarinet(eventBus) { , latestError , c , p - , textNode = "" + , textNode = undefined , numberNode = "" , slashed = false , closed = false @@ -79,7 +79,7 @@ function clarinet(eventBus) { var maxActual = 0; - if (textNode.length > MAX_BUFFER_LENGTH) { + if (textNode !== undefined && textNode.length > MAX_BUFFER_LENGTH) { emitError("Max buffer length exceeded: textNode"); maxActual = Math.max(maxActual, textNode.length); } @@ -100,10 +100,10 @@ function clarinet(eventBus) { eventBus(STREAM_END).on(handleStreamEnd); function emitError (errorString) { - if (textNode) { + if (textNode !== undefined) { emitValueOpen(textNode); emitValueClose(); - textNode = ""; + textNode = undefined; } latestError = Error(errorString + "\nLn: "+line+ @@ -138,10 +138,10 @@ function clarinet(eventBus) { if (state !== VALUE || depth !== 0) emitError("Unexpected end"); - if (textNode) { + if (textNode !== undefined) { emitValueOpen(textNode); emitValueClose(); - textNode = ""; + textNode = undefined; } closed = true; @@ -211,26 +211,26 @@ function clarinet(eventBus) { if(state === CLOSE_OBJECT) { stack.push(CLOSE_OBJECT); - if (textNode) { + if (textNode !== undefined) { // was previously (in upstream Clarinet) one event // - object open came with the text of the first emitValueOpen({}); emitSaxKey(textNode); - textNode = ""; + textNode = undefined; } depth++; } else { - if (textNode) { + if (textNode !== undefined) { emitSaxKey(textNode); - textNode = ""; + textNode = undefined; } } state = VALUE; } else if (c==='}') { - if (textNode) { + if (textNode !== undefined) { emitValueOpen(textNode); emitValueClose(); - textNode = ""; + textNode = undefined; } emitValueClose(); depth--; @@ -238,10 +238,10 @@ function clarinet(eventBus) { } else if(c===',') { if(state === CLOSE_OBJECT) stack.push(CLOSE_OBJECT); - if (textNode) { + if (textNode !== undefined) { emitValueOpen(textNode); emitValueClose(); - textNode = ""; + textNode = undefined; } state = OPEN_KEY; } else @@ -285,17 +285,17 @@ function clarinet(eventBus) { case CLOSE_ARRAY: if(c===',') { stack.push(CLOSE_ARRAY); - if (textNode) { + if (textNode !== undefined) { emitValueOpen(textNode); emitValueClose(); - textNode = ""; + textNode = undefined; } state = VALUE; } else if (c===']') { - if (textNode) { + if (textNode !== undefined) { emitValueOpen(textNode); emitValueClose(); - textNode = ""; + textNode = undefined; } emitValueClose(); depth--; @@ -307,6 +307,10 @@ function clarinet(eventBus) { continue; case STRING: + if (textNode === undefined) { + textNode = ""; + } + // thanks thejh, this is an about 50% performance improvement. var starti = i-1; @@ -330,10 +334,6 @@ function clarinet(eventBus) { if (c === '"' && !slashed) { state = stack.pop() || VALUE; textNode += chunk.substring(starti, i-1); - if(!textNode) { - emitValueOpen(""); - emitValueClose(); - } break; } if (c === '\\' && !slashed) { diff --git a/test/json/emptyKey.json b/test/json/emptyKey.json new file mode 100644 index 00000000..36314d8a --- /dev/null +++ b/test/json/emptyKey.json @@ -0,0 +1,4 @@ +{ + "myKey1": "myValue1", + "": "myValue2" +} \ No newline at end of file diff --git a/test/specs/oboe.integration.spec.js b/test/specs/oboe.integration.spec.js index f8c88a92..ac162a5e 100644 --- a/test/specs/oboe.integration.spec.js +++ b/test/specs/oboe.integration.spec.js @@ -111,6 +111,22 @@ }); }); + it('can read an empty key', function() { + + var fileStream = fs.createReadStream('test/json/emptyKey.json'); + + oboe(fileStream) + .node('!.*', callbackSpy) + .done(whenDoneFn); + + waitsFor(doneCalled, 'the request to have called done', ASYNC_TEST_TIMEOUT); + + runs(function () { + + expect( callbackSpy.calls.length ).toBe(2); + }); + }); + it('doesnt get confused if a stream has a "url" property', function() { var fileStream = fs.createReadStream('test/json/firstTenNaturalNumbers.json'); fileStream.url = 'http://howodd.com'; From 322f2c4952001b0810703cdabd58cb396121d0bd Mon Sep 17 00:00:00 2001 From: Juan Caicedo Date: Tue, 16 Aug 2016 20:09:52 -0700 Subject: [PATCH 08/11] update dist for empty keys bug fix --- dist/oboe-browser.js | 48 ++++++++++++++++++++-------------------- dist/oboe-browser.min.js | 2 +- dist/oboe-node.js | 48 ++++++++++++++++++++-------------------- 3 files changed, 49 insertions(+), 49 deletions(-) diff --git a/dist/oboe-browser.js b/dist/oboe-browser.js index a05072de..1d2ee7b7 100644 --- a/dist/oboe-browser.js +++ b/dist/oboe-browser.js @@ -4,7 +4,7 @@ // having a local undefined, window, Object etc allows slightly better minification: (function (window, Object, Array, Error, JSON, undefined ) { - // v2.1.2-2-g8cc8edc + // v2.1.2-14-g0737717 /* @@ -367,7 +367,7 @@ var emptyList = null, /** * Get the tail of a list. * - * Ie, head(cons(a,b)) = a + * Ie, tail(cons(a,b)) = b */ tail = attr(1); @@ -588,7 +588,7 @@ function clarinet(eventBus) { , latestError , c , p - , textNode = "" + , textNode = undefined , numberNode = "" , slashed = false , closed = false @@ -606,7 +606,7 @@ function clarinet(eventBus) { var maxActual = 0; - if (textNode.length > MAX_BUFFER_LENGTH) { + if (textNode !== undefined && textNode.length > MAX_BUFFER_LENGTH) { emitError("Max buffer length exceeded: textNode"); maxActual = Math.max(maxActual, textNode.length); } @@ -627,10 +627,10 @@ function clarinet(eventBus) { eventBus(STREAM_END).on(handleStreamEnd); function emitError (errorString) { - if (textNode) { + if (textNode !== undefined) { emitValueOpen(textNode); emitValueClose(); - textNode = ""; + textNode = undefined; } latestError = Error(errorString + "\nLn: "+line+ @@ -665,10 +665,10 @@ function clarinet(eventBus) { if (state !== VALUE || depth !== 0) emitError("Unexpected end"); - if (textNode) { + if (textNode !== undefined) { emitValueOpen(textNode); emitValueClose(); - textNode = ""; + textNode = undefined; } closed = true; @@ -738,26 +738,26 @@ function clarinet(eventBus) { if(state === CLOSE_OBJECT) { stack.push(CLOSE_OBJECT); - if (textNode) { + if (textNode !== undefined) { // was previously (in upstream Clarinet) one event // - object open came with the text of the first emitValueOpen({}); emitSaxKey(textNode); - textNode = ""; + textNode = undefined; } depth++; } else { - if (textNode) { + if (textNode !== undefined) { emitSaxKey(textNode); - textNode = ""; + textNode = undefined; } } state = VALUE; } else if (c==='}') { - if (textNode) { + if (textNode !== undefined) { emitValueOpen(textNode); emitValueClose(); - textNode = ""; + textNode = undefined; } emitValueClose(); depth--; @@ -765,10 +765,10 @@ function clarinet(eventBus) { } else if(c===',') { if(state === CLOSE_OBJECT) stack.push(CLOSE_OBJECT); - if (textNode) { + if (textNode !== undefined) { emitValueOpen(textNode); emitValueClose(); - textNode = ""; + textNode = undefined; } state = OPEN_KEY; } else @@ -812,17 +812,17 @@ function clarinet(eventBus) { case CLOSE_ARRAY: if(c===',') { stack.push(CLOSE_ARRAY); - if (textNode) { + if (textNode !== undefined) { emitValueOpen(textNode); emitValueClose(); - textNode = ""; + textNode = undefined; } state = VALUE; } else if (c===']') { - if (textNode) { + if (textNode !== undefined) { emitValueOpen(textNode); emitValueClose(); - textNode = ""; + textNode = undefined; } emitValueClose(); depth--; @@ -834,6 +834,10 @@ function clarinet(eventBus) { continue; case STRING: + if (textNode === undefined) { + textNode = ""; + } + // thanks thejh, this is an about 50% performance improvement. var starti = i-1; @@ -857,10 +861,6 @@ function clarinet(eventBus) { if (c === '"' && !slashed) { state = stack.pop() || VALUE; textNode += chunk.substring(starti, i-1); - if(!textNode) { - emitValueOpen(""); - emitValueClose(); - } break; } if (c === '\\' && !slashed) { diff --git a/dist/oboe-browser.min.js b/dist/oboe-browser.min.js index 3a414c4f..18f48d58 100644 --- a/dist/oboe-browser.min.js +++ b/dist/oboe-browser.min.js @@ -1 +1 @@ -!function(a,b,c,d,e,f){function g(a,b){return function(){return a.call(this,b.apply(this,arguments))}}function h(a){return function(b){return b[a]}}function i(a,b){return b.apply(f,a)}function j(a){var b=a.length-1,d=c.prototype.slice;if(0==b)return function(){return a.call(this,d.call(arguments))};if(1==b)return function(){return a.call(this,arguments[0],d.call(arguments,1))};var e=c(a.length);return function(){for(var c=0;b>c;c++)e[c]=arguments[c];return e[b]=d.call(arguments,b),a.apply(this,e)}}function k(a){return function(b,c){return a(c,b)}}function l(a,b){return function(c){return a(c)&&b(c)}}function m(){}function n(){return!0}function o(a){return function(){return a}}function p(a,b){return b&&b.constructor===a}function q(a){return a!==f}function r(a,c){return c instanceof b&&y(function(a){return a in c},a)}function s(a,b){return[a,b]}function t(a){return A(a.reduce(k(s),X))}function u(a){return w(function(a,b){return a.unshift(b),a},[],a)}function v(a,b){return b?s(a(Y(b)),v(a,Z(b))):X}function w(a,b,c){return c?a(w(a,b,Z(c)),Y(c)):b}function x(a,b,c){function d(a,c){return a?b(Y(a))?(c(Y(a)),Z(a)):s(Y(a),d(Z(a),c)):X}return d(a,c||m)}function y(a,b){return!b||a(Y(b))&&y(a,Z(b))}function z(a,b){a&&(Y(a).apply(null,b),z(Z(a),b))}function A(a){function b(a,c){return a?b(Z(a),s(Y(a),c)):c}return b(a,X)}function B(a,b){return b&&(a(Y(b))?Y(b):B(a,Z(b)))}function C(a){"use strict";function b(){var a=0;P.length>p&&(c("Max buffer length exceeded: textNode"),a=Math.max(a,P.length)),Q.length>p&&(c("Max buffer length exceeded: numberNode"),a=Math.max(a,Q.length)),O=p-a+Y}function c(a){P&&(m(P),n(),P=""),i=d(a+"\nLn: "+$+"\nCol: "+Z+"\nChr: "+j),o(N(f,f,i))}function e(){return T==s?(m({}),n(),void(S=!0)):((T!==t||0!==X)&&c("Unexpected end"),P&&(m(P),n(),P=""),void(S=!0))}function g(a){return"\r"==a||"\n"==a||" "==a||" "==a}function h(a){if(!i){if(S)return c("Cannot write after close");var d=0;for(j=a[0];j&&(k=j,j=a[d++]);)switch(Y++,"\n"==j?($++,Z=0):Z++,T){case s:if("{"===j)T=u;else if("["===j)T=w;else if(!g(j))return c("Non-whitespace before {[.");continue;case z:case u:if(g(j))continue;if(T===z)U.push(A);else{if("}"===j){m({}),n(),T=U.pop()||t;continue}U.push(v)}if('"'!==j)return c('Malformed object key should start with " ');T=y;continue;case A:case v:if(g(j))continue;if(":"===j)T===v?(U.push(v),P&&(m({}),l(P),P=""),X++):P&&(l(P),P=""),T=t;else if("}"===j)P&&(m(P),n(),P=""),n(),X--,T=U.pop()||t;else{if(","!==j)return c("Bad object");T===v&&U.push(v),P&&(m(P),n(),P=""),T=z}continue;case w:case t:if(g(j))continue;if(T===w){if(m([]),X++,T=t,"]"===j){n(),X--,T=U.pop()||t;continue}U.push(x)}if('"'===j)T=y;else if("{"===j)T=u;else if("["===j)T=w;else if("t"===j)T=B;else if("f"===j)T=E;else if("n"===j)T=I;else if("-"===j)Q+=j;else if("0"===j)Q+=j,T=M;else{if(-1==="123456789".indexOf(j))return c("Bad value");Q+=j,T=M}continue;case x:if(","===j)U.push(x),P&&(m(P),n(),P=""),T=t;else{if("]"!==j){if(g(j))continue;return c("Bad array")}P&&(m(P),n(),P=""),n(),X--,T=U.pop()||t}continue;case y:var e=d-1;a:for(;;){for(;W>0;)if(V+=j,j=a.charAt(d++),4===W?(P+=String.fromCharCode(parseInt(V,16)),W=0,e=d-1):W++,!j)break a;if('"'===j&&!R){T=U.pop()||t,P+=a.substring(e,d-1),P||(m(""),n());break}if("\\"===j&&!R&&(R=!0,P+=a.substring(e,d-1),j=a.charAt(d++),!j))break;if(R){if(R=!1,"n"===j?P+="\n":"r"===j?P+="\r":"t"===j?P+=" ":"f"===j?P+="\f":"b"===j?P+="\b":"u"===j?(W=1,V=""):P+=j,j=a.charAt(d++),e=d-1,j)continue;break}q.lastIndex=d;var f=q.exec(a);if(!f){d=a.length+1,P+=a.substring(e,d-1);break}if(d=f.index+1,j=a.charAt(f.index),!j){P+=a.substring(e,d-1);break}}continue;case B:if(!j)continue;if("r"!==j)return c("Invalid true started with t"+j);T=C;continue;case C:if(!j)continue;if("u"!==j)return c("Invalid true started with tr"+j);T=D;continue;case D:if(!j)continue;if("e"!==j)return c("Invalid true started with tru"+j);m(!0),n(),T=U.pop()||t;continue;case E:if(!j)continue;if("a"!==j)return c("Invalid false started with f"+j);T=F;continue;case F:if(!j)continue;if("l"!==j)return c("Invalid false started with fa"+j);T=G;continue;case G:if(!j)continue;if("s"!==j)return c("Invalid false started with fal"+j);T=H;continue;case H:if(!j)continue;if("e"!==j)return c("Invalid false started with fals"+j);m(!1),n(),T=U.pop()||t;continue;case I:if(!j)continue;if("u"!==j)return c("Invalid null started with n"+j);T=J;continue;case J:if(!j)continue;if("l"!==j)return c("Invalid null started with nu"+j);T=K;continue;case K:if(!j)continue;if("l"!==j)return c("Invalid null started with nul"+j);m(null),n(),T=U.pop()||t;continue;case L:if("."!==j)return c("Leading zero not followed by .");Q+=j,T=M;continue;case M:if(-1!=="0123456789".indexOf(j))Q+=j;else if("."===j){if(-1!==Q.indexOf("."))return c("Invalid number has two dots");Q+=j}else if("e"===j||"E"===j){if(-1!==Q.indexOf("e")||-1!==Q.indexOf("E"))return c("Invalid number has two exponential");Q+=j}else if("+"===j||"-"===j){if("e"!==k&&"E"!==k)return c("Invalid symbol in number");Q+=j}else Q&&(m(parseFloat(Q)),n(),Q=""),d--,T=U.pop()||t;continue;default:return c("Unknown state: "+T)}Y>=O&&b()}}var i,j,k,l=a(qa).emit,m=a(ra).emit,n=a(sa).emit,o=a(ja).emit,p=65536,q=/[\\"\n]/g,r=0,s=r++,t=r++,u=r++,v=r++,w=r++,x=r++,y=r++,z=r++,A=r++,B=r++,C=r++,D=r++,E=r++,F=r++,G=r++,H=r++,I=r++,J=r++,K=r++,L=r++,M=r,O=p,P="",Q="",R=!1,S=!1,T=s,U=[],V=null,W=0,X=0,Y=0,Z=0,$=1;a(na).on(h),a(oa).on(e)}function D(a,b){"use strict";function c(a){return function(b){d=a(d,b)}}var d,e={};for(var f in b)a(f).on(c(b[f]),e);a(ha).on(function(a){var b,c=Y(d),e=aa(c),f=Z(d);f&&(b=ba(Y(f)),b[e]=a)}),a(ia).on(function(){var a,b=Y(d),c=aa(b),e=Z(d);e&&(a=ba(Y(e)),delete a[c])}),a(pa).on(function(){for(var c in b)a(c).un(e)})}function E(a){var b={};return a&&a.split("\r\n").forEach(function(a){var c=a.indexOf(": ");b[a.substring(0,c)]=a.substring(c+2)}),b}function F(a,b){function c(a){return{"http:":80,"https:":443}[a]}function d(b){return b.port||c(b.protocol||a.protocol)}return!!(b.protocol&&b.protocol!=a.protocol||b.host&&b.host!=a.host||b.host&&d(b)!=d(a))}function G(a){var b=/(\w+:)?(?:\/\/)([\w.-]+)?(?::(\d+))?\/?/,c=b.exec(a)||[];return{protocol:c[1]||"",host:c[2]||"",port:c[3]||""}}function H(){return new XMLHttpRequest}function I(b,c,d,e,g,h,i){"use strict";function j(){var a=c.responseText,b=a.substr(m);b&&k(b),m=V(a)}var k=b(na).emit,l=b(ja).emit,m=0,n=!0;b(pa).on(function(){c.onreadystatechange=null,c.abort()}),"onprogress"in c&&(c.onprogress=j),c.onreadystatechange=function(){function a(){try{n&&b(ma).emit(c.status,E(c.getAllResponseHeaders())),n=!1}catch(a){}}switch(c.readyState){case 2:case 3:return a();case 4:a();var d=2==String(c.status)[0];d?(j(),b(oa).emit()):l(N(c.status,c.responseText))}};try{c.open(d,e,!0);for(var o in h)c.setRequestHeader(o,h[o]);F(a.location,G(e))||c.setRequestHeader("X-Requested-With","XMLHttpRequest"),c.withCredentials=i,c.send(g)}catch(p){a.setTimeout(T(l,N(f,f,p)),0)}}function J(a,b){return{key:a,node:b}}function K(a){function b(a,b){var d=ba(Y(a));return p(c,d)?f(a,V(d),b):a}function d(a,c){if(!a)return j(c),f(a,ca,c);var d=b(a,c),g=Z(d),h=aa(Y(d));return e(g,h,c),s(J(h,c),g)}function e(a,b,c){ba(Y(a))[b]=c}function f(a,b,c){a&&e(a,b,c);var d=s(J(b,c),a);return h(d),d}function g(a){return i(a),Z(a)||k(ba(Y(a)))}var h=a(fa).emit,i=a(ga).emit,j=a(la).emit,k=a(ka).emit,l={};return l[ra]=d,l[sa]=g,l[qa]=f,l}function L(a,b,c){function d(a){return function(b){return b.id==a}}var e,f;return{on:function(c,d){var g={listener:c,id:d||c};return b&&b.emit(a,c,g.id),e=s(g,e),f=s(c,f),this},emit:function(){z(f,arguments)},un:function(b){var g;e=x(e,d(b),function(a){g=a}),g&&(f=x(f,function(a){return a==g.listener}),c&&c.emit(a,g.listener,g.id))},listeners:function(){return f},hasListener:function(a){var b=a?d(a):n;return q(B(b,e))}}}function M(){function a(a){return c[a]=L(a,d,e)}function b(b){return c[b]||a(b)}var c={},d=a("newListener"),e=a("removeListener");return["emit","on","un"].forEach(function(a){b[a]=j(function(c,d){i(d,b(c)[a])})}),b}function N(a,b,c){try{var d=e.parse(b)}catch(f){}return{statusCode:a,body:b,jsonBody:d,thrown:c}}function O(a,b){function c(a,b,c){var d=A(c);a(b,u(Z(v(aa,d))),u(v(ba,d)))}function d(b,d,e){var f=a(b).emit;d.on(function(a){var b=e(a);b!==!1&&c(f,ba(b),a)},b),a("removeListener").on(function(c){c==b&&(a(c).listeners()||d.un(b))})}var e={node:a(ga),path:a(fa)};a("newListener").on(function(a){var c=/(node|path):(.*)/.exec(a);if(c){var f=e[c[1]];f.hasListener(a)||d(a,f,b(c[2]))}})}function P(a,b){function c(b,c){return a(b).on(e(c),c),n}function d(a,b,c){c=c||b;var d=e(b);return a.on(function(){var b=!1;n.forget=function(){b=!0},i(arguments,d),delete n.forget,b&&a.un(c)},c),n}function e(a){return function(){try{return a.apply(n,arguments)}catch(b){setTimeout(function(){throw b})}}}function f(b,c){return a(b+":"+c)}function g(a){return function(){var b=a.apply(this,arguments);q(b)&&(b==S.drop?s():t(b))}}function h(a,b,c){var e;e="node"==a?g(c):c,d(f(a,b),e,c)}function k(a,b){for(var c in b)h(a,c,b[c])}function l(a,b,c){return W(b)?h(a,b,c):k(a,b),n}var n,p=/^(node|path):./,r=a(ka),s=a(ia).emit,t=a(ha).emit,u=j(function(b,c){if(n[b])i(c,n[b]);else{var e=a(b),f=c[0];p.test(b)?d(e,f):e.on(f)}return n}),v=function(b,c,d){if("done"==b)r.un(c);else if("node"==b||"path"==b)a.un(b+":"+c,d);else{var e=c;a(b).un(e)}return n};return a(la).on(function(a){n.root=o(a)}),a(ma).on(function(a,b){n.header=function(a){return a?b[a]:b}}),n={on:u,addListener:u,removeListener:v,emit:a.emit,node:T(l,"node"),path:T(l,"path"),done:T(d,r),start:T(c,ma),fail:a(ja).on,abort:a(pa).emit,header:m,root:m,source:b}}function Q(a,b,c,d,e){var f=M();return b&&I(f,H(),a,b,c,d,e),C(f),D(f,K(f)),O(f,da),P(f,b)}function R(a,b,c,d,f,g,h){function i(a,b){return b===!1&&(a+=-1==a.indexOf("?")?"?":"&",a+="_="+(new Date).getTime()),a}return f=f?e.parse(e.stringify(f)):{},d?W(d)||(d=e.stringify(d),f["Content-Type"]=f["Content-Type"]||"application/json"):d=null,a(c||"GET",i(b,h),d,f,g||!1)}function S(a){var b=$("resume","pause","pipe"),c=T(r,b);return a?c(a)||W(a)?R(Q,a):R(Q,a.url,a.method,a.body,a.headers,a.withCredentials,a.cached):Q()}var T=j(function(a,b){var c=b.length;return j(function(d){for(var e=0;ec;c++)e[c]=arguments[c];return e[b]=d.call(arguments,b),a.apply(this,e)}}function k(a){return function(b,c){return a(c,b)}}function l(a,b){return function(c){return a(c)&&b(c)}}function m(){}function n(){return!0}function o(a){return function(){return a}}function p(a,b){return b&&b.constructor===a}function q(a){return a!==f}function r(a,c){return c instanceof b&&y(function(a){return a in c},a)}function s(a,b){return[a,b]}function t(a){return A(a.reduce(k(s),X))}function u(a){return w(function(a,b){return a.unshift(b),a},[],a)}function v(a,b){return b?s(a(Y(b)),v(a,Z(b))):X}function w(a,b,c){return c?a(w(a,b,Z(c)),Y(c)):b}function x(a,b,c){function d(a,c){return a?b(Y(a))?(c(Y(a)),Z(a)):s(Y(a),d(Z(a),c)):X}return d(a,c||m)}function y(a,b){return!b||a(Y(b))&&y(a,Z(b))}function z(a,b){a&&(Y(a).apply(null,b),z(Z(a),b))}function A(a){function b(a,c){return a?b(Z(a),s(Y(a),c)):c}return b(a,X)}function B(a,b){return b&&(a(Y(b))?Y(b):B(a,Z(b)))}function C(a){"use strict";function b(){var a=0;P!==f&&P.length>p&&(c("Max buffer length exceeded: textNode"),a=Math.max(a,P.length)),Q.length>p&&(c("Max buffer length exceeded: numberNode"),a=Math.max(a,Q.length)),O=p-a+Y}function c(a){P!==f&&(m(P),n(),P=f),i=d(a+"\nLn: "+$+"\nCol: "+Z+"\nChr: "+j),o(N(f,f,i))}function e(){return T==s?(m({}),n(),void(S=!0)):((T!==t||0!==X)&&c("Unexpected end"),P!==f&&(m(P),n(),P=f),void(S=!0))}function g(a){return"\r"==a||"\n"==a||" "==a||" "==a}function h(a){if(!i){if(S)return c("Cannot write after close");var d=0;for(j=a[0];j&&(k=j,j=a[d++]);)switch(Y++,"\n"==j?($++,Z=0):Z++,T){case s:if("{"===j)T=u;else if("["===j)T=w;else if(!g(j))return c("Non-whitespace before {[.");continue;case z:case u:if(g(j))continue;if(T===z)U.push(A);else{if("}"===j){m({}),n(),T=U.pop()||t;continue}U.push(v)}if('"'!==j)return c('Malformed object key should start with " ');T=y;continue;case A:case v:if(g(j))continue;if(":"===j)T===v?(U.push(v),P!==f&&(m({}),l(P),P=f),X++):P!==f&&(l(P),P=f),T=t;else if("}"===j)P!==f&&(m(P),n(),P=f),n(),X--,T=U.pop()||t;else{if(","!==j)return c("Bad object");T===v&&U.push(v),P!==f&&(m(P),n(),P=f),T=z}continue;case w:case t:if(g(j))continue;if(T===w){if(m([]),X++,T=t,"]"===j){n(),X--,T=U.pop()||t;continue}U.push(x)}if('"'===j)T=y;else if("{"===j)T=u;else if("["===j)T=w;else if("t"===j)T=B;else if("f"===j)T=E;else if("n"===j)T=I;else if("-"===j)Q+=j;else if("0"===j)Q+=j,T=M;else{if(-1==="123456789".indexOf(j))return c("Bad value");Q+=j,T=M}continue;case x:if(","===j)U.push(x),P!==f&&(m(P),n(),P=f),T=t;else{if("]"!==j){if(g(j))continue;return c("Bad array")}P!==f&&(m(P),n(),P=f),n(),X--,T=U.pop()||t}continue;case y:P===f&&(P="");var e=d-1;a:for(;;){for(;W>0;)if(V+=j,j=a.charAt(d++),4===W?(P+=String.fromCharCode(parseInt(V,16)),W=0,e=d-1):W++,!j)break a;if('"'===j&&!R){T=U.pop()||t,P+=a.substring(e,d-1);break}if("\\"===j&&!R&&(R=!0,P+=a.substring(e,d-1),j=a.charAt(d++),!j))break;if(R){if(R=!1,"n"===j?P+="\n":"r"===j?P+="\r":"t"===j?P+=" ":"f"===j?P+="\f":"b"===j?P+="\b":"u"===j?(W=1,V=""):P+=j,j=a.charAt(d++),e=d-1,j)continue;break}q.lastIndex=d;var h=q.exec(a);if(!h){d=a.length+1,P+=a.substring(e,d-1);break}if(d=h.index+1,j=a.charAt(h.index),!j){P+=a.substring(e,d-1);break}}continue;case B:if(!j)continue;if("r"!==j)return c("Invalid true started with t"+j);T=C;continue;case C:if(!j)continue;if("u"!==j)return c("Invalid true started with tr"+j);T=D;continue;case D:if(!j)continue;if("e"!==j)return c("Invalid true started with tru"+j);m(!0),n(),T=U.pop()||t;continue;case E:if(!j)continue;if("a"!==j)return c("Invalid false started with f"+j);T=F;continue;case F:if(!j)continue;if("l"!==j)return c("Invalid false started with fa"+j);T=G;continue;case G:if(!j)continue;if("s"!==j)return c("Invalid false started with fal"+j);T=H;continue;case H:if(!j)continue;if("e"!==j)return c("Invalid false started with fals"+j);m(!1),n(),T=U.pop()||t;continue;case I:if(!j)continue;if("u"!==j)return c("Invalid null started with n"+j);T=J;continue;case J:if(!j)continue;if("l"!==j)return c("Invalid null started with nu"+j);T=K;continue;case K:if(!j)continue;if("l"!==j)return c("Invalid null started with nul"+j);m(null),n(),T=U.pop()||t;continue;case L:if("."!==j)return c("Leading zero not followed by .");Q+=j,T=M;continue;case M:if(-1!=="0123456789".indexOf(j))Q+=j;else if("."===j){if(-1!==Q.indexOf("."))return c("Invalid number has two dots");Q+=j}else if("e"===j||"E"===j){if(-1!==Q.indexOf("e")||-1!==Q.indexOf("E"))return c("Invalid number has two exponential");Q+=j}else if("+"===j||"-"===j){if("e"!==k&&"E"!==k)return c("Invalid symbol in number");Q+=j}else Q&&(m(parseFloat(Q)),n(),Q=""),d--,T=U.pop()||t;continue;default:return c("Unknown state: "+T)}Y>=O&&b()}}var i,j,k,l=a(qa).emit,m=a(ra).emit,n=a(sa).emit,o=a(ja).emit,p=65536,q=/[\\"\n]/g,r=0,s=r++,t=r++,u=r++,v=r++,w=r++,x=r++,y=r++,z=r++,A=r++,B=r++,C=r++,D=r++,E=r++,F=r++,G=r++,H=r++,I=r++,J=r++,K=r++,L=r++,M=r,O=p,P=f,Q="",R=!1,S=!1,T=s,U=[],V=null,W=0,X=0,Y=0,Z=0,$=1;a(na).on(h),a(oa).on(e)}function D(a,b){"use strict";function c(a){return function(b){d=a(d,b)}}var d,e={};for(var f in b)a(f).on(c(b[f]),e);a(ha).on(function(a){var b,c=Y(d),e=aa(c),f=Z(d);f&&(b=ba(Y(f)),b[e]=a)}),a(ia).on(function(){var a,b=Y(d),c=aa(b),e=Z(d);e&&(a=ba(Y(e)),delete a[c])}),a(pa).on(function(){for(var c in b)a(c).un(e)})}function E(a){var b={};return a&&a.split("\r\n").forEach(function(a){var c=a.indexOf(": ");b[a.substring(0,c)]=a.substring(c+2)}),b}function F(a,b){function c(a){return{"http:":80,"https:":443}[a]}function d(b){return b.port||c(b.protocol||a.protocol)}return!!(b.protocol&&b.protocol!=a.protocol||b.host&&b.host!=a.host||b.host&&d(b)!=d(a))}function G(a){var b=/(\w+:)?(?:\/\/)([\w.-]+)?(?::(\d+))?\/?/,c=b.exec(a)||[];return{protocol:c[1]||"",host:c[2]||"",port:c[3]||""}}function H(){return new XMLHttpRequest}function I(b,c,d,e,g,h,i){"use strict";function j(){var a=c.responseText,b=a.substr(m);b&&k(b),m=V(a)}var k=b(na).emit,l=b(ja).emit,m=0,n=!0;b(pa).on(function(){c.onreadystatechange=null,c.abort()}),"onprogress"in c&&(c.onprogress=j),c.onreadystatechange=function(){function a(){try{n&&b(ma).emit(c.status,E(c.getAllResponseHeaders())),n=!1}catch(a){}}switch(c.readyState){case 2:case 3:return a();case 4:a();var d=2==String(c.status)[0];d?(j(),b(oa).emit()):l(N(c.status,c.responseText))}};try{c.open(d,e,!0);for(var o in h)c.setRequestHeader(o,h[o]);F(a.location,G(e))||c.setRequestHeader("X-Requested-With","XMLHttpRequest"),c.withCredentials=i,c.send(g)}catch(p){a.setTimeout(T(l,N(f,f,p)),0)}}function J(a,b){return{key:a,node:b}}function K(a){function b(a,b){var d=ba(Y(a));return p(c,d)?f(a,V(d),b):a}function d(a,c){if(!a)return j(c),f(a,ca,c);var d=b(a,c),g=Z(d),h=aa(Y(d));return e(g,h,c),s(J(h,c),g)}function e(a,b,c){ba(Y(a))[b]=c}function f(a,b,c){a&&e(a,b,c);var d=s(J(b,c),a);return h(d),d}function g(a){return i(a),Z(a)||k(ba(Y(a)))}var h=a(fa).emit,i=a(ga).emit,j=a(la).emit,k=a(ka).emit,l={};return l[ra]=d,l[sa]=g,l[qa]=f,l}function L(a,b,c){function d(a){return function(b){return b.id==a}}var e,f;return{on:function(c,d){var g={listener:c,id:d||c};return b&&b.emit(a,c,g.id),e=s(g,e),f=s(c,f),this},emit:function(){z(f,arguments)},un:function(b){var g;e=x(e,d(b),function(a){g=a}),g&&(f=x(f,function(a){return a==g.listener}),c&&c.emit(a,g.listener,g.id))},listeners:function(){return f},hasListener:function(a){var b=a?d(a):n;return q(B(b,e))}}}function M(){function a(a){return c[a]=L(a,d,e)}function b(b){return c[b]||a(b)}var c={},d=a("newListener"),e=a("removeListener");return["emit","on","un"].forEach(function(a){b[a]=j(function(c,d){i(d,b(c)[a])})}),b}function N(a,b,c){try{var d=e.parse(b)}catch(f){}return{statusCode:a,body:b,jsonBody:d,thrown:c}}function O(a,b){function c(a,b,c){var d=A(c);a(b,u(Z(v(aa,d))),u(v(ba,d)))}function d(b,d,e){var f=a(b).emit;d.on(function(a){var b=e(a);b!==!1&&c(f,ba(b),a)},b),a("removeListener").on(function(c){c==b&&(a(c).listeners()||d.un(b))})}var e={node:a(ga),path:a(fa)};a("newListener").on(function(a){var c=/(node|path):(.*)/.exec(a);if(c){var f=e[c[1]];f.hasListener(a)||d(a,f,b(c[2]))}})}function P(a,b){function c(b,c){return a(b).on(e(c),c),n}function d(a,b,c){c=c||b;var d=e(b);return a.on(function(){var b=!1;n.forget=function(){b=!0},i(arguments,d),delete n.forget,b&&a.un(c)},c),n}function e(a){return function(){try{return a.apply(n,arguments)}catch(b){setTimeout(function(){throw b})}}}function f(b,c){return a(b+":"+c)}function g(a){return function(){var b=a.apply(this,arguments);q(b)&&(b==S.drop?s():t(b))}}function h(a,b,c){var e;e="node"==a?g(c):c,d(f(a,b),e,c)}function k(a,b){for(var c in b)h(a,c,b[c])}function l(a,b,c){return W(b)?h(a,b,c):k(a,b),n}var n,p=/^(node|path):./,r=a(ka),s=a(ia).emit,t=a(ha).emit,u=j(function(b,c){if(n[b])i(c,n[b]);else{var e=a(b),f=c[0];p.test(b)?d(e,f):e.on(f)}return n}),v=function(b,c,d){if("done"==b)r.un(c);else if("node"==b||"path"==b)a.un(b+":"+c,d);else{var e=c;a(b).un(e)}return n};return a(la).on(function(a){n.root=o(a)}),a(ma).on(function(a,b){n.header=function(a){return a?b[a]:b}}),n={on:u,addListener:u,removeListener:v,emit:a.emit,node:T(l,"node"),path:T(l,"path"),done:T(d,r),start:T(c,ma),fail:a(ja).on,abort:a(pa).emit,header:m,root:m,source:b}}function Q(a,b,c,d,e){var f=M();return b&&I(f,H(),a,b,c,d,e),C(f),D(f,K(f)),O(f,da),P(f,b)}function R(a,b,c,d,f,g,h){function i(a,b){return b===!1&&(a+=-1==a.indexOf("?")?"?":"&",a+="_="+(new Date).getTime()),a}return f=f?e.parse(e.stringify(f)):{},d?W(d)||(d=e.stringify(d),f["Content-Type"]=f["Content-Type"]||"application/json"):d=null,a(c||"GET",i(b,h),d,f,g||!1)}function S(a){var b=$("resume","pause","pipe"),c=T(r,b);return a?c(a)||W(a)?R(Q,a):R(Q,a.url,a.method,a.body,a.headers,a.withCredentials,a.cached):Q()}var T=j(function(a,b){var c=b.length;return j(function(d){for(var e=0;e MAX_BUFFER_LENGTH) { + if (textNode !== undefined && textNode.length > MAX_BUFFER_LENGTH) { emitError("Max buffer length exceeded: textNode"); maxActual = Math.max(maxActual, textNode.length); } @@ -626,10 +626,10 @@ function clarinet(eventBus) { eventBus(STREAM_END).on(handleStreamEnd); function emitError (errorString) { - if (textNode) { + if (textNode !== undefined) { emitValueOpen(textNode); emitValueClose(); - textNode = ""; + textNode = undefined; } latestError = Error(errorString + "\nLn: "+line+ @@ -664,10 +664,10 @@ function clarinet(eventBus) { if (state !== VALUE || depth !== 0) emitError("Unexpected end"); - if (textNode) { + if (textNode !== undefined) { emitValueOpen(textNode); emitValueClose(); - textNode = ""; + textNode = undefined; } closed = true; @@ -737,26 +737,26 @@ function clarinet(eventBus) { if(state === CLOSE_OBJECT) { stack.push(CLOSE_OBJECT); - if (textNode) { + if (textNode !== undefined) { // was previously (in upstream Clarinet) one event // - object open came with the text of the first emitValueOpen({}); emitSaxKey(textNode); - textNode = ""; + textNode = undefined; } depth++; } else { - if (textNode) { + if (textNode !== undefined) { emitSaxKey(textNode); - textNode = ""; + textNode = undefined; } } state = VALUE; } else if (c==='}') { - if (textNode) { + if (textNode !== undefined) { emitValueOpen(textNode); emitValueClose(); - textNode = ""; + textNode = undefined; } emitValueClose(); depth--; @@ -764,10 +764,10 @@ function clarinet(eventBus) { } else if(c===',') { if(state === CLOSE_OBJECT) stack.push(CLOSE_OBJECT); - if (textNode) { + if (textNode !== undefined) { emitValueOpen(textNode); emitValueClose(); - textNode = ""; + textNode = undefined; } state = OPEN_KEY; } else @@ -811,17 +811,17 @@ function clarinet(eventBus) { case CLOSE_ARRAY: if(c===',') { stack.push(CLOSE_ARRAY); - if (textNode) { + if (textNode !== undefined) { emitValueOpen(textNode); emitValueClose(); - textNode = ""; + textNode = undefined; } state = VALUE; } else if (c===']') { - if (textNode) { + if (textNode !== undefined) { emitValueOpen(textNode); emitValueClose(); - textNode = ""; + textNode = undefined; } emitValueClose(); depth--; @@ -833,6 +833,10 @@ function clarinet(eventBus) { continue; case STRING: + if (textNode === undefined) { + textNode = ""; + } + // thanks thejh, this is an about 50% performance improvement. var starti = i-1; @@ -856,10 +860,6 @@ function clarinet(eventBus) { if (c === '"' && !slashed) { state = stack.pop() || VALUE; textNode += chunk.substring(starti, i-1); - if(!textNode) { - emitValueOpen(""); - emitValueClose(); - } break; } if (c === '\\' && !slashed) { From e72690422e23c5d904e9682dfeaa23d9a8e8fb81 Mon Sep 17 00:00:00 2001 From: Juan Caicedo Date: Mon, 10 Oct 2016 10:05:51 -0500 Subject: [PATCH 09/11] 2.1.3 --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 737167e7..b36e5a15 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "oboe", "title": "Oboe.js", - "version": "2.1.2", + "version": "2.1.3", "description": "Oboe.js reads json, giving you the objects as they are found without waiting for the stream to finish", "main": "./dist/oboe-node.js", "browser": "./dist/oboe-browser.js", @@ -78,4 +78,4 @@ "Parsers & Compilers" ] } -} \ No newline at end of file +} From 2a518d889e0f90f36ccc861b7c9eb476279534a5 Mon Sep 17 00:00:00 2001 From: Juan Caicedo Date: Mon, 10 Oct 2016 10:06:50 -0500 Subject: [PATCH 10/11] build version 2.1.3 --- dist/oboe-browser.js | 2 +- dist/oboe-node.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/dist/oboe-browser.js b/dist/oboe-browser.js index 1d2ee7b7..240f9e59 100644 --- a/dist/oboe-browser.js +++ b/dist/oboe-browser.js @@ -4,7 +4,7 @@ // having a local undefined, window, Object etc allows slightly better minification: (function (window, Object, Array, Error, JSON, undefined ) { - // v2.1.2-14-g0737717 + // v2.1.3 /* diff --git a/dist/oboe-node.js b/dist/oboe-node.js index c7854d1d..1d35b899 100644 --- a/dist/oboe-node.js +++ b/dist/oboe-node.js @@ -3,7 +3,7 @@ module.exports = (function () { - // v2.1.2-14-g0737717 + // v2.1.3 /* From c85b5c496d7efa4f43e3f065d0a5074ebab399db Mon Sep 17 00:00:00 2001 From: Juan Caicedo Date: Sun, 23 Oct 2016 16:47:19 -0500 Subject: [PATCH 11/11] fix how integration tests spy on setTimeout in node --- test/specs/oboe.integration.spec.js | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/test/specs/oboe.integration.spec.js b/test/specs/oboe.integration.spec.js index c3dadda8..0092bbff 100644 --- a/test/specs/oboe.integration.spec.js +++ b/test/specs/oboe.integration.spec.js @@ -1,6 +1,14 @@ (function(Platform) { + // Used to spy on global functions like setTimeout + var globalContext; + if ( !Platform.isNode ) { + globalContext = window; + } else { + globalContext = GLOBAL; + } + describe("oboe integration (real http)", function() { var oboe = Platform.isNode @@ -284,7 +292,7 @@ it('continues to parse after a callback throws an exception', function () { - spyOn(window, 'setTimeout'); + spyOn(globalContext, 'setTimeout'); oboe(testUrl('static/json/tenRecords.json')) .node('{id name}', function(){ @@ -301,9 +309,9 @@ ); runs(function () { - expect(window.setTimeout.calls.length).toEqual(10); + expect(globalContext.setTimeout.calls.length).toEqual(10); for(var i = 0; i < 10; i++) { - expect(window.setTimeout.calls[i].args[0]).toThrow('uh oh!') + expect(globalContext.setTimeout.calls[i].args[0]).toThrow('uh oh!') } }); }) @@ -674,7 +682,7 @@ var callbackError = new Error('I am a bad callback'); stubCallback = jasmine.createSpy('error callback').andThrow(callbackError); - spyOn(window, 'setTimeout'); + spyOn(globalContext, 'setTimeout'); oboe(testUrl('static/json/firstTenNaturalNumbers.json')) .node('!.*', stubCallback) @@ -683,7 +691,7 @@ }, 'the callback to be called', ASYNC_TEST_TIMEOUT) runs( function() { - expect(window.setTimeout.mostRecentCall.args[0]).toThrow(callbackError) + expect(globalContext.setTimeout.mostRecentCall.args[0]).toThrow(callbackError) }); }) @@ -692,7 +700,7 @@ var callbackError = new Error('I am a bad callback'); stubCallback = jasmine.createSpy('error callback').andThrow(callbackError); - spyOn(window, 'setTimeout'); + spyOn(globalContext, 'setTimeout'); oboe(testUrl('static/json/firstTenNaturalNumbers.json')) .done(stubCallback) @@ -702,7 +710,7 @@ runs( function() { - expect(window.setTimeout.mostRecentCall.args[0]).toThrow(callbackError) + expect(globalContext.setTimeout.mostRecentCall.args[0]).toThrow(callbackError) }); })