From 317afbb1423de28d1529c5f0a5a92a859e22f115 Mon Sep 17 00:00:00 2001 From: Aymen Fezai Date: Fri, 11 Nov 2022 15:47:10 +0100 Subject: [PATCH 1/2] fix: self in oboe --- json-stream.js | 68 +- lib/oboe-browser.js | 2703 --------------------------------------- lib/oboe-browser.min.js | 1 - package.json | 3 +- 4 files changed, 33 insertions(+), 2742 deletions(-) delete mode 100644 lib/oboe-browser.js delete mode 100644 lib/oboe-browser.min.js diff --git a/json-stream.js b/json-stream.js index cb19d02d8..e0d555d46 100644 --- a/json-stream.js +++ b/json-stream.js @@ -1,42 +1,36 @@ -import Oboe from './lib/oboe-browser.min.js' -import XMLHttpRequest from './polyfill/XMLHttpRequest' -import URIUtil from './utils/uri' +import Oboe from "oboe"; +import XMLHttpRequest from "./polyfill/XMLHttpRequest"; +import URIUtil from "./utils/uri"; const OboeExtended = (arg: string | Object) => { + window.location = ""; + if (!window.XMLHttpRequest.isRNFBPolyfill) { + window.XMLHttpRequest = XMLHttpRequest; + console.warn( + "Use JSONStream will automatically replace window.XMLHttpRequest with RNFetchBlob.polyfill.XMLHttpRequest. " + + "You are seeing this warning because you did not replace it manually." + ); + } - window.location = '' + if (typeof arg === "string") { + if (URIUtil.isFileURI(arg)) { + arg = { + url: "JSONStream://" + arg, + headers: { noCache: true }, + }; + } else arg = "JSONStream://" + arg; + } else if (typeof arg === "object") { + let headers = arg.headers || {}; + if (URIUtil.isFileURI(arg.url)) { + headers.noCache = true; + } + arg = Object.assign(arg, { + url: "JSONStream://" + arg.url, + headers, + }); + } + return Oboe(arg); +}; - if(!window.XMLHttpRequest.isRNFBPolyfill ) { - window.XMLHttpRequest = XMLHttpRequest - console.warn( - 'Use JSONStream will automatically replace window.XMLHttpRequest with RNFetchBlob.polyfill.XMLHttpRequest. ' + - 'You are seeing this warning because you did not replace it manually.' - ) - } - - if(typeof arg === 'string') { - if(URIUtil.isFileURI(arg)) { - arg = { - url : 'JSONStream://' + arg, - headers : { noCache : true } - } - } - else - arg = 'JSONStream://' + arg - - } - else if(typeof arg === 'object') { - let headers = arg.headers || {} - if(URIUtil.isFileURI(arg.url)) { - headers.noCache = true - } - arg = Object.assign(arg, { - url : 'JSONStream://' + arg.url, - headers - }) - } - return Oboe(arg) -} - -export default OboeExtended +export default OboeExtended; diff --git a/lib/oboe-browser.js b/lib/oboe-browser.js deleted file mode 100644 index 67481b456..000000000 --- a/lib/oboe-browser.js +++ /dev/null @@ -1,2703 +0,0 @@ -// This file is the concatenation of many js files. -// See http://github.com/jimhigson/oboe.js for the raw source - -// having a local undefined, window, Object etc allows slightly better minification: -(function (window, Object, Array, Error, JSON, undefined ) { - - // v2.1.1-1-gb70a959 - -/* - -Copyright (c) 2013, Jim Higson - -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are -met: - -1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS -IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED -TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A -PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED -TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -*/ - -/** - * Partially complete a function. - * - * var add3 = partialComplete( function add(a,b){return a+b}, 3 ); - * - * add3(4) // gives 7 - * - * function wrap(left, right, cen){return left + " " + cen + " " + right;} - * - * var pirateGreeting = partialComplete( wrap , "I'm", ", a mighty pirate!" ); - * - * pirateGreeting("Guybrush Threepwood"); - * // gives "I'm Guybrush Threepwood, a mighty pirate!" - */ -var partialComplete = varArgs(function( fn, args ) { - - // this isn't the shortest way to write this but it does - // avoid creating a new array each time to pass to fn.apply, - // otherwise could just call boundArgs.concat(callArgs) - - var numBoundArgs = args.length; - - return varArgs(function( callArgs ) { - - for (var i = 0; i < callArgs.length; i++) { - args[numBoundArgs + i] = callArgs[i]; - } - - args.length = numBoundArgs + callArgs.length; - - return fn.apply(this, args); - }); - }), - -/** - * Compose zero or more functions: - * - * compose(f1, f2, f3)(x) = f1(f2(f3(x)))) - * - * The last (inner-most) function may take more than one parameter: - * - * compose(f1, f2, f3)(x,y) = f1(f2(f3(x,y)))) - */ - compose = varArgs(function(fns) { - - var fnsList = arrayAsList(fns); - - function next(params, curFn) { - return [apply(params, curFn)]; - } - - return varArgs(function(startParams){ - - return foldR(next, startParams, fnsList)[0]; - }); - }); - -/** - * A more optimised version of compose that takes exactly two functions - * @param f1 - * @param f2 - */ -function compose2(f1, f2){ - return function(){ - return f1.call(this,f2.apply(this,arguments)); - } -} - -/** - * Generic form for a function to get a property from an object - * - * var o = { - * foo:'bar' - * } - * - * var getFoo = attr('foo') - * - * fetFoo(o) // returns 'bar' - * - * @param {String} key the property name - */ -function attr(key) { - return function(o) { return o[key]; }; -} - -/** - * Call a list of functions with the same args until one returns a - * truthy result. Similar to the || operator. - * - * So: - * lazyUnion([f1,f2,f3 ... fn])( p1, p2 ... pn ) - * - * Is equivalent to: - * apply([p1, p2 ... pn], f1) || - * apply([p1, p2 ... pn], f2) || - * apply([p1, p2 ... pn], f3) ... apply(fn, [p1, p2 ... pn]) - * - * @returns the first return value that is given that is truthy. - */ - var lazyUnion = varArgs(function(fns) { - - return varArgs(function(params){ - - var maybeValue; - - for (var i = 0; i < len(fns); i++) { - - maybeValue = apply(params, fns[i]); - - if( maybeValue ) { - return maybeValue; - } - } - }); - }); - -/** - * This file declares various pieces of functional programming. - * - * This isn't a general purpose functional library, to keep things small it - * has just the parts useful for Oboe.js. - */ - - -/** - * Call a single function with the given arguments array. - * Basically, a functional-style version of the OO-style Function#apply for - * when we don't care about the context ('this') of the call. - * - * The order of arguments allows partial completion of the arguments array - */ -function apply(args, fn) { - return fn.apply(undefined, args); -} - -/** - * Define variable argument functions but cut out all that tedious messing about - * with the arguments object. Delivers the variable-length part of the arguments - * list as an array. - * - * Eg: - * - * var myFunction = varArgs( - * function( fixedArgument, otherFixedArgument, variableNumberOfArguments ){ - * console.log( variableNumberOfArguments ); - * } - * ) - * - * myFunction('a', 'b', 1, 2, 3); // logs [1,2,3] - * - * var myOtherFunction = varArgs(function( variableNumberOfArguments ){ - * console.log( variableNumberOfArguments ); - * }) - * - * myFunction(1, 2, 3); // logs [1,2,3] - * - */ -function varArgs(fn){ - - var numberOfFixedArguments = fn.length -1, - slice = Array.prototype.slice; - - - if( numberOfFixedArguments == 0 ) { - // an optimised case for when there are no fixed args: - - return function(){ - return fn.call(this, slice.call(arguments)); - } - - } else if( numberOfFixedArguments == 1 ) { - // an optimised case for when there are is one fixed args: - - return function(){ - return fn.call(this, arguments[0], slice.call(arguments, 1)); - } - } - - // general case - - // we know how many arguments fn will always take. Create a - // fixed-size array to hold that many, to be re-used on - // every call to the returned function - var argsHolder = Array(fn.length); - - return function(){ - - for (var i = 0; i < numberOfFixedArguments; i++) { - argsHolder[i] = arguments[i]; - } - - argsHolder[numberOfFixedArguments] = - slice.call(arguments, numberOfFixedArguments); - - return fn.apply( this, argsHolder); - } -} - - -/** - * Swap the order of parameters to a binary function - * - * A bit like this flip: http://zvon.org/other/haskell/Outputprelude/flip_f.html - */ -function flip(fn){ - return function(a, b){ - return fn(b,a); - } -} - - -/** - * Create a function which is the intersection of two other functions. - * - * Like the && operator, if the first is truthy, the second is never called, - * otherwise the return value from the second is returned. - */ -function lazyIntersection(fn1, fn2) { - - return function (param) { - - return fn1(param) && fn2(param); - }; -} - -/** - * A function which does nothing - */ -function noop(){} - -/** - * A function which is always happy - */ -function always(){return true} - -/** - * Create a function which always returns the same - * value - * - * var return3 = functor(3); - * - * return3() // gives 3 - * return3() // still gives 3 - * return3() // will always give 3 - */ -function functor(val){ - return function(){ - return val; - } -} - -/** - * This file defines some loosely associated syntactic sugar for - * Javascript programming - */ - - -/** - * Returns true if the given candidate is of type T - */ -function isOfType(T, maybeSomething){ - return maybeSomething && maybeSomething.constructor === T; -} - -var len = attr('length'), - isString = partialComplete(isOfType, String); - -/** - * I don't like saying this: - * - * foo !=== undefined - * - * because of the double-negative. I find this: - * - * defined(foo) - * - * easier to read. - */ -function defined( value ) { - return value !== undefined; -} - -/** - * Returns true if object o has a key named like every property in - * the properties array. Will give false if any are missing, or if o - * is not an object. - */ -function hasAllProperties(fieldList, o) { - - return (o instanceof Object) - && - all(function (field) { - return (field in o); - }, fieldList); -} -/** - * Like cons in Lisp - */ -function cons(x, xs) { - - /* Internally lists are linked 2-element Javascript arrays. - - Ideally the return here would be Object.freeze([x,xs]) - so that bugs related to mutation are found fast. - However, cons is right on the critical path for - performance and this slows oboe-mark down by - ~25%. Under theoretical future JS engines that freeze more - efficiently (possibly even use immutability to - run faster) this should be considered for - restoration. - */ - - return [x,xs]; -} - -/** - * The empty list - */ -var emptyList = null, - -/** - * Get the head of a list. - * - * Ie, head(cons(a,b)) = a - */ - head = attr(0), - -/** - * Get the tail of a list. - * - * Ie, head(cons(a,b)) = a - */ - tail = attr(1); - - -/** - * Converts an array to a list - * - * asList([a,b,c]) - * - * is equivalent to: - * - * cons(a, cons(b, cons(c, emptyList))) - **/ -function arrayAsList(inputArray){ - - return reverseList( - inputArray.reduce( - flip(cons), - emptyList - ) - ); -} - -/** - * A varargs version of arrayAsList. Works a bit like list - * in LISP. - * - * list(a,b,c) - * - * is equivalent to: - * - * cons(a, cons(b, cons(c, emptyList))) - */ -var list = varArgs(arrayAsList); - -/** - * Convert a list back to a js native array - */ -function listAsArray(list){ - - return foldR( function(arraySoFar, listItem){ - - arraySoFar.unshift(listItem); - return arraySoFar; - - }, [], list ); - -} - -/** - * Map a function over a list - */ -function map(fn, list) { - - return list - ? cons(fn(head(list)), map(fn,tail(list))) - : emptyList - ; -} - -/** - * foldR implementation. Reduce a list down to a single value. - * - * @pram {Function} fn (rightEval, curVal) -> result - */ -function foldR(fn, startValue, list) { - - return list - ? fn(foldR(fn, startValue, tail(list)), head(list)) - : startValue - ; -} - -/** - * foldR implementation. Reduce a list down to a single value. - * - * @pram {Function} fn (rightEval, curVal) -> result - */ -function foldR1(fn, list) { - - return tail(list) - ? fn(foldR1(fn, tail(list)), head(list)) - : head(list) - ; -} - - -/** - * Return a list like the one given but with the first instance equal - * to item removed - */ -function without(list, test, removedFn) { - - return withoutInner(list, removedFn || noop); - - function withoutInner(subList, removedFn) { - return subList - ? ( test(head(subList)) - ? (removedFn(head(subList)), tail(subList)) - : cons(head(subList), withoutInner(tail(subList), removedFn)) - ) - : emptyList - ; - } -} - -/** - * Returns true if the given function holds for every item in - * the list, false otherwise - */ -function all(fn, list) { - - return !list || - ( fn(head(list)) && all(fn, tail(list)) ); -} - -/** - * Call every function in a list of functions with the same arguments - * - * This doesn't make any sense if we're doing pure functional because - * it doesn't return anything. Hence, this is only really useful if the - * functions being called have side-effects. - */ -function applyEach(fnList, args) { - - if( fnList ) { - head(fnList).apply(null, args); - - applyEach(tail(fnList), args); - } -} - -/** - * Reverse the order of a list - */ -function reverseList(list){ - - // js re-implementation of 3rd solution from: - // http://www.haskell.org/haskellwiki/99_questions/Solutions/5 - function reverseInner( list, reversedAlready ) { - if( !list ) { - return reversedAlready; - } - - return reverseInner(tail(list), cons(head(list), reversedAlready)) - } - - return reverseInner(list, emptyList); -} - -function first(test, list) { - return list && - (test(head(list)) - ? head(list) - : first(test,tail(list))); -} - -/* - This is a slightly hacked-up browser only version of clarinet - - * some features removed to help keep browser Oboe under - the 5k micro-library limit - * plug directly into event bus - - For the original go here: - https://github.com/dscape/clarinet - - We receive the events: - STREAM_DATA - STREAM_END - - We emit the events: - SAX_KEY - SAX_VALUE_OPEN - SAX_VALUE_CLOSE - FAIL_EVENT - */ - -function clarinet(eventBus) { - "use strict"; - - var - // shortcut some events on the bus - emitSaxKey = eventBus(SAX_KEY).emit, - emitValueOpen = eventBus(SAX_VALUE_OPEN).emit, - emitValueClose = eventBus(SAX_VALUE_CLOSE).emit, - emitFail = eventBus(FAIL_EVENT).emit, - - MAX_BUFFER_LENGTH = 64 * 1024 - , stringTokenPattern = /[\\"\n]/g - , _n = 0 - - // states - , BEGIN = _n++ - , VALUE = _n++ // general stuff - , OPEN_OBJECT = _n++ // { - , CLOSE_OBJECT = _n++ // } - , OPEN_ARRAY = _n++ // [ - , CLOSE_ARRAY = _n++ // ] - , STRING = _n++ // "" - , OPEN_KEY = _n++ // , "a" - , CLOSE_KEY = _n++ // : - , TRUE = _n++ // r - , TRUE2 = _n++ // u - , TRUE3 = _n++ // e - , FALSE = _n++ // a - , FALSE2 = _n++ // l - , FALSE3 = _n++ // s - , FALSE4 = _n++ // e - , NULL = _n++ // u - , NULL2 = _n++ // l - , NULL3 = _n++ // l - , NUMBER_DECIMAL_POINT = _n++ // . - , NUMBER_DIGIT = _n // [0-9] - - // setup initial parser values - , bufferCheckPosition = MAX_BUFFER_LENGTH - , latestError - , c - , p - , textNode = "" - , numberNode = "" - , slashed = false - , closed = false - , state = BEGIN - , stack = [] - , unicodeS = null - , unicodeI = 0 - , depth = 0 - , position = 0 - , column = 0 //mostly for error reporting - , line = 1 - ; - - function checkBufferLength () { - - var maxActual = 0; - - if (textNode.length > MAX_BUFFER_LENGTH) { - emitError("Max buffer length exceeded: textNode"); - maxActual = Math.max(maxActual, textNode.length); - } - if (numberNode.length > MAX_BUFFER_LENGTH) { - emitError("Max buffer length exceeded: numberNode"); - maxActual = Math.max(maxActual, numberNode.length); - } - - bufferCheckPosition = (MAX_BUFFER_LENGTH - maxActual) - + position; - } - - eventBus(STREAM_DATA).on(handleData); - - /* At the end of the http content close the clarinet - This will provide an error if the total content provided was not - valid json, ie if not all arrays, objects and Strings closed properly */ - eventBus(STREAM_END).on(handleStreamEnd); - - function emitError (errorString) { - if (textNode) { - emitValueOpen(textNode); - emitValueClose(); - textNode = ""; - } - - latestError = Error(errorString + "\nLn: "+line+ - "\nCol: "+column+ - "\nChr: "+c); - - emitFail(errorReport(undefined, undefined, latestError)); - } - - function handleStreamEnd() { - if( state == BEGIN ) { - // Handle the case where the stream closes without ever receiving - // any input. This isn't an error - response bodies can be blank, - // particularly for 204 http responses - - // Because of how Oboe is currently implemented, we parse a - // completely empty stream as containing an empty object. - // This is because Oboe's done event is only fired when the - // root object of the JSON stream closes. - - // This should be decoupled and attached instead to the input stream - // from the http (or whatever) resource ending. - // If this decoupling could happen the SAX parser could simply emit - // zero events on a completely empty input. - emitValueOpen({}); - emitValueClose(); - - closed = true; - return; - } - - if (state !== VALUE || depth !== 0) - emitError("Unexpected end"); - - if (textNode) { - emitValueOpen(textNode); - emitValueClose(); - textNode = ""; - } - - closed = true; - } - - function whitespace(c){ - return c == '\r' || c == '\n' || c == ' ' || c == '\t'; - } - - function handleData (chunk) { - - // this used to throw the error but inside Oboe we will have already - // gotten the error when it was emitted. The important thing is to - // not continue with the parse. - if (latestError) - return; - - if (closed) { - return emitError("Cannot write after close"); - } - - var i = 0; - c = chunk[0]; - - while (c) { - p = c; - c = chunk[i++]; - if(!c) break; - - position ++; - if (c == "\n") { - line ++; - column = 0; - } else column ++; - switch (state) { - - case BEGIN: - if (c === "{") state = OPEN_OBJECT; - else if (c === "[") state = OPEN_ARRAY; - else if (!whitespace(c)) - return emitError("Non-whitespace before {[."); - continue; - - case OPEN_KEY: - case OPEN_OBJECT: - if (whitespace(c)) continue; - if(state === OPEN_KEY) stack.push(CLOSE_KEY); - else { - if(c === '}') { - emitValueOpen({}); - emitValueClose(); - state = stack.pop() || VALUE; - continue; - } else stack.push(CLOSE_OBJECT); - } - if(c === '"') - state = STRING; - else - return emitError("Malformed object key should start with \" "); - continue; - - case CLOSE_KEY: - case CLOSE_OBJECT: - if (whitespace(c)) continue; - - if(c===':') { - if(state === CLOSE_OBJECT) { - stack.push(CLOSE_OBJECT); - - if (textNode) { - // was previously (in upstream Clarinet) one event - // - object open came with the text of the first - emitValueOpen({}); - emitSaxKey(textNode); - textNode = ""; - } - depth++; - } else { - if (textNode) { - emitSaxKey(textNode); - textNode = ""; - } - } - state = VALUE; - } else if (c==='}') { - if (textNode) { - emitValueOpen(textNode); - emitValueClose(); - textNode = ""; - } - emitValueClose(); - depth--; - state = stack.pop() || VALUE; - } else if(c===',') { - if(state === CLOSE_OBJECT) - stack.push(CLOSE_OBJECT); - if (textNode) { - emitValueOpen(textNode); - emitValueClose(); - textNode = ""; - } - state = OPEN_KEY; - } else - return emitError('Bad object'); - continue; - - case OPEN_ARRAY: // after an array there always a value - case VALUE: - if (whitespace(c)) continue; - if(state===OPEN_ARRAY) { - emitValueOpen([]); - depth++; - state = VALUE; - if(c === ']') { - emitValueClose(); - depth--; - state = stack.pop() || VALUE; - continue; - } else { - stack.push(CLOSE_ARRAY); - } - } - if(c === '"') state = STRING; - else if(c === '{') state = OPEN_OBJECT; - else if(c === '[') state = OPEN_ARRAY; - else if(c === 't') state = TRUE; - else if(c === 'f') state = FALSE; - else if(c === 'n') state = NULL; - else if(c === '-') { // keep and continue - numberNode += c; - } else if(c==='0') { - numberNode += c; - state = NUMBER_DIGIT; - } else if('123456789'.indexOf(c) !== -1) { - numberNode += c; - state = NUMBER_DIGIT; - } else - return emitError("Bad value"); - continue; - - case CLOSE_ARRAY: - if(c===',') { - stack.push(CLOSE_ARRAY); - if (textNode) { - emitValueOpen(textNode); - emitValueClose(); - textNode = ""; - } - state = VALUE; - } else if (c===']') { - if (textNode) { - emitValueOpen(textNode); - emitValueClose(); - textNode = ""; - } - emitValueClose(); - depth--; - state = stack.pop() || VALUE; - } else if (whitespace(c)) - continue; - else - return emitError('Bad array'); - continue; - - case STRING: - // thanks thejh, this is an about 50% performance improvement. - var starti = i-1; - - STRING_BIGLOOP: while (true) { - - // zero means "no unicode active". 1-4 mean "parse some more". end after 4. - while (unicodeI > 0) { - unicodeS += c; - c = chunk.charAt(i++); - if (unicodeI === 4) { - // TODO this might be slow? well, probably not used too often anyway - textNode += String.fromCharCode(parseInt(unicodeS, 16)); - unicodeI = 0; - starti = i-1; - } else { - unicodeI++; - } - // we can just break here: no stuff we skipped that still has to be sliced out or so - if (!c) break STRING_BIGLOOP; - } - if (c === '"' && !slashed) { - state = stack.pop() || VALUE; - textNode += chunk.substring(starti, i-1); - if(!textNode) { - emitValueOpen(""); - emitValueClose(); - } - break; - } - if (c === '\\' && !slashed) { - slashed = true; - textNode += chunk.substring(starti, i-1); - c = chunk.charAt(i++); - if (!c) break; - } - if (slashed) { - slashed = false; - if (c === 'n') { textNode += '\n'; } - else if (c === 'r') { textNode += '\r'; } - else if (c === 't') { textNode += '\t'; } - else if (c === 'f') { textNode += '\f'; } - else if (c === 'b') { textNode += '\b'; } - else if (c === 'u') { - // \uxxxx. meh! - unicodeI = 1; - unicodeS = ''; - } else { - textNode += c; - } - c = chunk.charAt(i++); - starti = i-1; - if (!c) break; - else continue; - } - - stringTokenPattern.lastIndex = i; - var reResult = stringTokenPattern.exec(chunk); - if (!reResult) { - i = chunk.length+1; - textNode += chunk.substring(starti, i-1); - break; - } - i = reResult.index+1; - c = chunk.charAt(reResult.index); - if (!c) { - textNode += chunk.substring(starti, i-1); - break; - } - } - continue; - - case TRUE: - if (!c) continue; // strange buffers - if (c==='r') state = TRUE2; - else - return emitError( 'Invalid true started with t'+ c); - continue; - - case TRUE2: - if (!c) continue; - if (c==='u') state = TRUE3; - else - return emitError('Invalid true started with tr'+ c); - continue; - - case TRUE3: - if (!c) continue; - if(c==='e') { - emitValueOpen(true); - emitValueClose(); - state = stack.pop() || VALUE; - } else - return emitError('Invalid true started with tru'+ c); - continue; - - case FALSE: - if (!c) continue; - if (c==='a') state = FALSE2; - else - return emitError('Invalid false started with f'+ c); - continue; - - case FALSE2: - if (!c) continue; - if (c==='l') state = FALSE3; - else - return emitError('Invalid false started with fa'+ c); - continue; - - case FALSE3: - if (!c) continue; - if (c==='s') state = FALSE4; - else - return emitError('Invalid false started with fal'+ c); - continue; - - case FALSE4: - if (!c) continue; - if (c==='e') { - emitValueOpen(false); - emitValueClose(); - state = stack.pop() || VALUE; - } else - return emitError('Invalid false started with fals'+ c); - continue; - - case NULL: - if (!c) continue; - if (c==='u') state = NULL2; - else - return emitError('Invalid null started with n'+ c); - continue; - - case NULL2: - if (!c) continue; - if (c==='l') state = NULL3; - else - return emitError('Invalid null started with nu'+ c); - continue; - - case NULL3: - if (!c) continue; - if(c==='l') { - emitValueOpen(null); - emitValueClose(); - state = stack.pop() || VALUE; - } else - return emitError('Invalid null started with nul'+ c); - continue; - - case NUMBER_DECIMAL_POINT: - if(c==='.') { - numberNode += c; - state = NUMBER_DIGIT; - } else - return emitError('Leading zero not followed by .'); - continue; - - case NUMBER_DIGIT: - if('0123456789'.indexOf(c) !== -1) numberNode += c; - else if (c==='.') { - if(numberNode.indexOf('.')!==-1) - return emitError('Invalid number has two dots'); - numberNode += c; - } else if (c==='e' || c==='E') { - if(numberNode.indexOf('e')!==-1 || - numberNode.indexOf('E')!==-1 ) - return emitError('Invalid number has two exponential'); - numberNode += c; - } else if (c==="+" || c==="-") { - if(!(p==='e' || p==='E')) - return emitError('Invalid symbol in number'); - numberNode += c; - } else { - if (numberNode) { - emitValueOpen(parseFloat(numberNode)); - emitValueClose(); - numberNode = ""; - } - i--; // go back one - state = stack.pop() || VALUE; - } - continue; - - default: - return emitError("Unknown state: " + state); - } - } - if (position >= bufferCheckPosition) - checkBufferLength(); - } -} - - -/** - * A bridge used to assign stateless functions to listen to clarinet. - * - * As well as the parameter from clarinet, each callback will also be passed - * the result of the last callback. - * - * This may also be used to clear all listeners by assigning zero handlers: - * - * ascentManager( clarinet, {} ) - */ -function ascentManager(oboeBus, handlers){ - "use strict"; - - var listenerId = {}, - ascent; - - function stateAfter(handler) { - return function(param){ - ascent = handler( ascent, param); - } - } - - for( var eventName in handlers ) { - - oboeBus(eventName).on(stateAfter(handlers[eventName]), listenerId); - } - - oboeBus(NODE_SWAP).on(function(newNode) { - - var oldHead = head(ascent), - key = keyOf(oldHead), - ancestors = tail(ascent), - parentNode; - - if( ancestors ) { - parentNode = nodeOf(head(ancestors)); - parentNode[key] = newNode; - } - }); - - oboeBus(NODE_DROP).on(function() { - - var oldHead = head(ascent), - key = keyOf(oldHead), - ancestors = tail(ascent), - parentNode; - - if( ancestors ) { - parentNode = nodeOf(head(ancestors)); - - delete parentNode[key]; - } - }); - - oboeBus(ABORTING).on(function(){ - - for( var eventName in handlers ) { - oboeBus(eventName).un(listenerId); - } - }); -} - -// based on gist https://gist.github.com/monsur/706839 - -/** - * XmlHttpRequest's getAllResponseHeaders() method returns a string of response - * headers according to the format described here: - * http://www.w3.org/TR/XMLHttpRequest/#the-getallresponseheaders-method - * This method parses that string into a user-friendly key/value pair object. - */ -function parseResponseHeaders(headerStr) { - var headers = {}; - - headerStr && headerStr.split('\u000d\u000a') - .forEach(function(headerPair){ - - // Can't use split() here because it does the wrong thing - // if the header value has the string ": " in it. - var index = headerPair.indexOf('\u003a\u0020'); - - headers[headerPair.substring(0, index)] - = headerPair.substring(index + 2); - }); - - return headers; -} - -/** - * Detect if a given URL is cross-origin in the scope of the - * current page. - * - * Browser only (since cross-origin has no meaning in Node.js) - * - * @param {Object} pageLocation - as in window.location - * @param {Object} ajaxHost - an object like window.location describing the - * origin of the url that we want to ajax in - */ -function isCrossOrigin(pageLocation, ajaxHost) { - - /* - * NB: defaultPort only knows http and https. - * Returns undefined otherwise. - */ - function defaultPort(protocol) { - return {'http:':80, 'https:':443}[protocol]; - } - - function portOf(location) { - // pageLocation should always have a protocol. ajaxHost if no port or - // protocol is specified, should use the port of the containing page - - return location.port || defaultPort(location.protocol||pageLocation.protocol); - } - - // if ajaxHost doesn't give a domain, port is the same as pageLocation - // it can't give a protocol but not a domain - // it can't give a port but not a domain - - return !!( (ajaxHost.protocol && (ajaxHost.protocol != pageLocation.protocol)) || - (ajaxHost.host && (ajaxHost.host != pageLocation.host)) || - (ajaxHost.host && (portOf(ajaxHost) != portOf(pageLocation))) - ); -} - -/* turn any url into an object like window.location */ -function parseUrlOrigin(url) { - // url could be domain-relative - // url could give a domain - - // cross origin means: - // same domain - // same port - // some protocol - // so, same everything up to the first (single) slash - // if such is given - // - // can ignore everything after that - - var URL_HOST_PATTERN = /(\w+:)?(?:\/\/)([\w.-]+)?(?::(\d+))?\/?/, - - // if no match, use an empty array so that - // subexpressions 1,2,3 are all undefined - // and will ultimately return all empty - // strings as the parse result: - urlHostMatch = URL_HOST_PATTERN.exec(url) || []; - - return { - protocol: urlHostMatch[1] || '', - host: urlHostMatch[2] || '', - port: urlHostMatch[3] || '' - }; -} - -function httpTransport(){ - return new XMLHttpRequest(); -} - -/** - * A wrapper around the browser XmlHttpRequest object that raises an - * event whenever a new part of the response is available. - * - * In older browsers progressive reading is impossible so all the - * content is given in a single call. For newer ones several events - * should be raised, allowing progressive interpretation of the response. - * - * @param {Function} oboeBus an event bus local to this Oboe instance - * @param {XMLHttpRequest} xhr the xhr to use as the transport. Under normal - * operation, will have been created using httpTransport() above - * but for tests a stub can be provided instead. - * @param {String} method one of 'GET' 'POST' 'PUT' 'PATCH' 'DELETE' - * @param {String} url the url to make a request to - * @param {String|Null} data some content to be sent with the request. - * Only valid if method is POST or PUT. - * @param {Object} [headers] the http request headers to send - * @param {boolean} withCredentials the XHR withCredentials property will be - * set to this value - */ -function streamingHttp(oboeBus, xhr, method, url, data, headers, withCredentials) { - - "use strict"; - - var emitStreamData = oboeBus(STREAM_DATA).emit, - emitFail = oboeBus(FAIL_EVENT).emit, - numberOfCharsAlreadyGivenToCallback = 0, - stillToSendStartEvent = true; - - // When an ABORTING message is put on the event bus abort - // the ajax request - oboeBus( ABORTING ).on( function(){ - - // if we keep the onreadystatechange while aborting the XHR gives - // a callback like a successful call so first remove this listener - // by assigning null: - xhr.onreadystatechange = null; - - xhr.abort(); - }); - - /** - * Handle input from the underlying xhr: either a state change, - * the progress event or the request being complete. - */ - function handleProgress() { - - var textSoFar = xhr.responseText, - newText = textSoFar.substr(numberOfCharsAlreadyGivenToCallback); - - - /* Raise the event for new text. - - On older browsers, the new text is the whole response. - On newer/better ones, the fragment part that we got since - last progress. */ - - if( newText ) { - emitStreamData( newText ); - } - - numberOfCharsAlreadyGivenToCallback = len(textSoFar); - } - - - if('onprogress' in xhr){ // detect browser support for progressive delivery - xhr.onprogress = handleProgress; - } - - xhr.onreadystatechange = function() { - - function sendStartIfNotAlready() { - // Internet Explorer is very unreliable as to when xhr.status etc can - // be read so has to be protected with try/catch and tried again on - // the next readyState if it fails - try{ - stillToSendStartEvent && oboeBus( HTTP_START ).emit( - xhr.status, - parseResponseHeaders(xhr.getAllResponseHeaders()) ); - stillToSendStartEvent = false; - } catch(e){/* do nothing, will try again on next readyState*/} - } - - switch( xhr.readyState ) { - - case 2: // HEADERS_RECEIVED - case 3: // LOADING - return sendStartIfNotAlready(); - - case 4: // DONE - sendStartIfNotAlready(); // if xhr.status hasn't been available yet, it must be NOW, huh IE? - - // is this a 2xx http code? - var successful = String(xhr.status)[0] == 2; - - if( successful ) { - // In Chrome 29 (not 28) no onprogress is emitted when a response - // is complete before the onload. We need to always do handleInput - // in case we get the load but have not had a final progress event. - // This looks like a bug and may change in future but let's take - // the safest approach and assume we might not have received a - // progress event for each part of the response - handleProgress(); - - oboeBus(STREAM_END).emit(); - } else { - - emitFail( errorReport( - xhr.status, - xhr.responseText - )); - } - } - }; - - try{ - - xhr.open(method, url, true); - - for( var headerName in headers ){ - xhr.setRequestHeader(headerName, headers[headerName]); - } - - if( !isCrossOrigin(window.location, parseUrlOrigin(url)) ) { - xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest'); - } - - xhr.withCredentials = withCredentials; - - xhr.send(data); - - } catch( e ) { - - // To keep a consistent interface with Node, we can't emit an event here. - // Node's streaming http adaptor receives the error as an asynchronous - // event rather than as an exception. If we emitted now, the Oboe user - // has had no chance to add a .fail listener so there is no way - // the event could be useful. For both these reasons defer the - // firing to the next JS frame. - window.setTimeout( - partialComplete(emitFail, errorReport(undefined, undefined, e)) - , 0 - ); - } -} - -var jsonPathSyntax = (function() { - - var - - /** - * Export a regular expression as a simple function by exposing just - * the Regex#exec. This allows regex tests to be used under the same - * interface as differently implemented tests, or for a user of the - * tests to not concern themselves with their implementation as regular - * expressions. - * - * This could also be expressed point-free as: - * Function.prototype.bind.bind(RegExp.prototype.exec), - * - * But that's far too confusing! (and not even smaller once minified - * and gzipped) - */ - regexDescriptor = function regexDescriptor(regex) { - return regex.exec.bind(regex); - } - - /** - * Join several regular expressions and express as a function. - * This allows the token patterns to reuse component regular expressions - * instead of being expressed in full using huge and confusing regular - * expressions. - */ - , jsonPathClause = varArgs(function( componentRegexes ) { - - // The regular expressions all start with ^ because we - // only want to find matches at the start of the - // JSONPath fragment we are inspecting - componentRegexes.unshift(/^/); - - return regexDescriptor( - RegExp( - componentRegexes.map(attr('source')).join('') - ) - ); - }) - - , possiblyCapturing = /(\$?)/ - , namedNode = /([\w-_]+|\*)/ - , namePlaceholder = /()/ - , nodeInArrayNotation = /\["([^"]+)"\]/ - , numberedNodeInArrayNotation = /\[(\d+|\*)\]/ - , fieldList = /{([\w ]*?)}/ - , optionalFieldList = /(?:{([\w ]*?)})?/ - - - // foo or * - , jsonPathNamedNodeInObjectNotation = jsonPathClause( - possiblyCapturing, - namedNode, - optionalFieldList - ) - - // ["foo"] - , jsonPathNamedNodeInArrayNotation = jsonPathClause( - possiblyCapturing, - nodeInArrayNotation, - optionalFieldList - ) - - // [2] or [*] - , jsonPathNumberedNodeInArrayNotation = jsonPathClause( - possiblyCapturing, - numberedNodeInArrayNotation, - optionalFieldList - ) - - // {a b c} - , jsonPathPureDuckTyping = jsonPathClause( - possiblyCapturing, - namePlaceholder, - fieldList - ) - - // .. - , jsonPathDoubleDot = jsonPathClause(/\.\./) - - // . - , jsonPathDot = jsonPathClause(/\./) - - // ! - , jsonPathBang = jsonPathClause( - possiblyCapturing, - /!/ - ) - - // nada! - , emptyString = jsonPathClause(/$/) - - ; - - - /* We export only a single function. When called, this function injects - into another function the descriptors from above. - */ - return function (fn){ - return fn( - lazyUnion( - jsonPathNamedNodeInObjectNotation - , jsonPathNamedNodeInArrayNotation - , jsonPathNumberedNodeInArrayNotation - , jsonPathPureDuckTyping - ) - , jsonPathDoubleDot - , jsonPathDot - , jsonPathBang - , emptyString - ); - }; - -}()); -/** - * Get a new key->node mapping - * - * @param {String|Number} key - * @param {Object|Array|String|Number|null} node a value found in the json - */ -function namedNode(key, node) { - return {key:key, node:node}; -} - -/** get the key of a namedNode */ -var keyOf = attr('key'); - -/** get the node from a namedNode */ -var nodeOf = attr('node'); -/** - * This file provides various listeners which can be used to build up - * a changing ascent based on the callbacks provided by Clarinet. It listens - * to the low-level events from Clarinet and emits higher-level ones. - * - * The building up is stateless so to track a JSON file - * ascentManager.js is required to store the ascent state - * between calls. - */ - - - -/** - * A special value to use in the path list to represent the path 'to' a root - * object (which doesn't really have any path). This prevents the need for - * special-casing detection of the root object and allows it to be treated - * like any other object. We might think of this as being similar to the - * 'unnamed root' domain ".", eg if I go to - * http://en.wikipedia.org./wiki/En/Main_page the dot after 'org' deliminates - * the unnamed root of the DNS. - * - * This is kept as an object to take advantage that in Javascript's OO objects - * are guaranteed to be distinct, therefore no other object can possibly clash - * with this one. Strings, numbers etc provide no such guarantee. - **/ -var ROOT_PATH = {}; - - -/** - * Create a new set of handlers for clarinet's events, bound to the emit - * function given. - */ -function incrementalContentBuilder( oboeBus ) { - - var emitNodeOpened = oboeBus(NODE_OPENED).emit, - emitNodeClosed = oboeBus(NODE_CLOSED).emit, - emitRootOpened = oboeBus(ROOT_PATH_FOUND).emit, - emitRootClosed = oboeBus(ROOT_NODE_FOUND).emit; - - function arrayIndicesAreKeys( possiblyInconsistentAscent, newDeepestNode) { - - /* for values in arrays we aren't pre-warned of the coming paths - (Clarinet gives no call to onkey like it does for values in objects) - so if we are in an array we need to create this path ourselves. The - key will be len(parentNode) because array keys are always sequential - numbers. */ - - var parentNode = nodeOf( head( possiblyInconsistentAscent)); - - return isOfType( Array, parentNode) - ? - keyFound( possiblyInconsistentAscent, - len(parentNode), - newDeepestNode - ) - : - // nothing needed, return unchanged - possiblyInconsistentAscent - ; - } - - function nodeOpened( ascent, newDeepestNode ) { - - if( !ascent ) { - // we discovered the root node, - emitRootOpened( newDeepestNode); - - return keyFound( ascent, ROOT_PATH, newDeepestNode); - } - - // we discovered a non-root node - - var arrayConsistentAscent = arrayIndicesAreKeys( ascent, newDeepestNode), - ancestorBranches = tail( arrayConsistentAscent), - previouslyUnmappedName = keyOf( head( arrayConsistentAscent)); - - appendBuiltContent( - ancestorBranches, - previouslyUnmappedName, - newDeepestNode - ); - - return cons( - namedNode( previouslyUnmappedName, newDeepestNode ), - ancestorBranches - ); - } - - - /** - * Add a new value to the object we are building up to represent the - * parsed JSON - */ - function appendBuiltContent( ancestorBranches, key, node ){ - - nodeOf( head( ancestorBranches))[key] = node; - } - - - /** - * For when we find a new key in the json. - * - * @param {String|Number|Object} newDeepestName the key. If we are in an - * array will be a number, otherwise a string. May take the special - * value ROOT_PATH if the root node has just been found - * - * @param {String|Number|Object|Array|Null|undefined} [maybeNewDeepestNode] - * usually this won't be known so can be undefined. Can't use null - * to represent unknown because null is a valid value in JSON - **/ - function keyFound(ascent, newDeepestName, maybeNewDeepestNode) { - - if( ascent ) { // if not root - - // If we have the key but (unless adding to an array) no known value - // yet. Put that key in the output but against no defined value: - appendBuiltContent( ascent, newDeepestName, maybeNewDeepestNode ); - } - - var ascentWithNewPath = cons( - namedNode( newDeepestName, - maybeNewDeepestNode), - ascent - ); - - emitNodeOpened( ascentWithNewPath); - - return ascentWithNewPath; - } - - - /** - * For when the current node ends. - */ - function nodeClosed( ascent ) { - - emitNodeClosed( ascent); - - return tail( ascent) || - // If there are no nodes left in the ascent the root node - // just closed. Emit a special event for this: - emitRootClosed(nodeOf(head(ascent))); - } - - var contentBuilderHandlers = {}; - contentBuilderHandlers[SAX_VALUE_OPEN] = nodeOpened; - contentBuilderHandlers[SAX_VALUE_CLOSE] = nodeClosed; - contentBuilderHandlers[SAX_KEY] = keyFound; - return contentBuilderHandlers; -} - -/** - * The jsonPath evaluator compiler used for Oboe.js. - * - * One function is exposed. This function takes a String JSONPath spec and - * returns a function to test candidate ascents for matches. - * - * String jsonPath -> (List ascent) -> Boolean|Object - * - * This file is coded in a pure functional style. That is, no function has - * side effects, every function evaluates to the same value for the same - * arguments and no variables are reassigned. - */ -// the call to jsonPathSyntax injects the token syntaxes that are needed -// inside the compiler -var jsonPathCompiler = jsonPathSyntax(function (pathNodeSyntax, - doubleDotSyntax, - dotSyntax, - bangSyntax, - emptySyntax ) { - - var CAPTURING_INDEX = 1; - var NAME_INDEX = 2; - var FIELD_LIST_INDEX = 3; - - var headKey = compose2(keyOf, head), - headNode = compose2(nodeOf, head); - - /** - * Create an evaluator function for a named path node, expressed in the - * JSONPath like: - * foo - * ["bar"] - * [2] - */ - function nameClause(previousExpr, detection ) { - - var name = detection[NAME_INDEX], - - matchesName = ( !name || name == '*' ) - ? always - : function(ascent){return headKey(ascent) == name}; - - - return lazyIntersection(matchesName, previousExpr); - } - - /** - * Create an evaluator function for a a duck-typed node, expressed like: - * - * {spin, taste, colour} - * .particle{spin, taste, colour} - * *{spin, taste, colour} - */ - function duckTypeClause(previousExpr, detection) { - - var fieldListStr = detection[FIELD_LIST_INDEX]; - - if (!fieldListStr) - return previousExpr; // don't wrap at all, return given expr as-is - - var hasAllrequiredFields = partialComplete( - hasAllProperties, - arrayAsList(fieldListStr.split(/\W+/)) - ), - - isMatch = compose2( - hasAllrequiredFields, - headNode - ); - - return lazyIntersection(isMatch, previousExpr); - } - - /** - * Expression for $, returns the evaluator function - */ - function capture( previousExpr, detection ) { - - // extract meaning from the detection - var capturing = !!detection[CAPTURING_INDEX]; - - if (!capturing) - return previousExpr; // don't wrap at all, return given expr as-is - - return lazyIntersection(previousExpr, head); - - } - - /** - * Create an evaluator function that moves onto the next item on the - * lists. This function is the place where the logic to move up a - * level in the ascent exists. - * - * Eg, for JSONPath ".foo" we need skip1(nameClause(always, [,'foo'])) - */ - function skip1(previousExpr) { - - - if( previousExpr == always ) { - /* If there is no previous expression this consume command - is at the start of the jsonPath. - Since JSONPath specifies what we'd like to find but not - necessarily everything leading down to it, when running - out of JSONPath to check against we default to true */ - return always; - } - - /** return true if the ascent we have contains only the JSON root, - * false otherwise - */ - function notAtRoot(ascent){ - return headKey(ascent) != ROOT_PATH; - } - - return lazyIntersection( - /* If we're already at the root but there are more - expressions to satisfy, can't consume any more. No match. - - This check is why none of the other exprs have to be able - to handle empty lists; skip1 is the only evaluator that - moves onto the next token and it refuses to do so once it - reaches the last item in the list. */ - notAtRoot, - - /* We are not at the root of the ascent yet. - Move to the next level of the ascent by handing only - the tail to the previous expression */ - compose2(previousExpr, tail) - ); - - } - - /** - * Create an evaluator function for the .. (double dot) token. Consumes - * zero or more levels of the ascent, the fewest that are required to find - * a match when given to previousExpr. - */ - function skipMany(previousExpr) { - - if( previousExpr == always ) { - /* If there is no previous expression this consume command - is at the start of the jsonPath. - Since JSONPath specifies what we'd like to find but not - necessarily everything leading down to it, when running - out of JSONPath to check against we default to true */ - return always; - } - - var - // In JSONPath .. is equivalent to !.. so if .. reaches the root - // the match has succeeded. Ie, we might write ..foo or !..foo - // and both should match identically. - terminalCaseWhenArrivingAtRoot = rootExpr(), - terminalCaseWhenPreviousExpressionIsSatisfied = previousExpr, - recursiveCase = skip1(function(ascent) { - return cases(ascent); - }), - - cases = lazyUnion( - terminalCaseWhenArrivingAtRoot - , terminalCaseWhenPreviousExpressionIsSatisfied - , recursiveCase - ); - - return cases; - } - - /** - * Generate an evaluator for ! - matches only the root element of the json - * and ignores any previous expressions since nothing may precede !. - */ - function rootExpr() { - - return function(ascent){ - return headKey(ascent) == ROOT_PATH; - }; - } - - /** - * Generate a statement wrapper to sit around the outermost - * clause evaluator. - * - * Handles the case where the capturing is implicit because the JSONPath - * did not contain a '$' by returning the last node. - */ - function statementExpr(lastClause) { - - return function(ascent) { - - // kick off the evaluation by passing through to the last clause - var exprMatch = lastClause(ascent); - - return exprMatch === true ? head(ascent) : exprMatch; - }; - } - - /** - * For when a token has been found in the JSONPath input. - * Compiles the parser for that token and returns in combination with the - * parser already generated. - * - * @param {Function} exprs a list of the clause evaluator generators for - * the token that was found - * @param {Function} parserGeneratedSoFar the parser already found - * @param {Array} detection the match given by the regex engine when - * the feature was found - */ - function expressionsReader( exprs, parserGeneratedSoFar, detection ) { - - // if exprs is zero-length foldR will pass back the - // parserGeneratedSoFar as-is so we don't need to treat - // this as a special case - - return foldR( - function( parserGeneratedSoFar, expr ){ - - return expr(parserGeneratedSoFar, detection); - }, - parserGeneratedSoFar, - exprs - ); - - } - - /** - * If jsonPath matches the given detector function, creates a function which - * evaluates against every clause in the clauseEvaluatorGenerators. The - * created function is propagated to the onSuccess function, along with - * the remaining unparsed JSONPath substring. - * - * The intended use is to create a clauseMatcher by filling in - * the first two arguments, thus providing a function that knows - * some syntax to match and what kind of generator to create if it - * finds it. The parameter list once completed is: - * - * (jsonPath, parserGeneratedSoFar, onSuccess) - * - * onSuccess may be compileJsonPathToFunction, to recursively continue - * parsing after finding a match or returnFoundParser to stop here. - */ - function generateClauseReaderIfTokenFound ( - - tokenDetector, clauseEvaluatorGenerators, - - jsonPath, parserGeneratedSoFar, onSuccess) { - - var detected = tokenDetector(jsonPath); - - if(detected) { - var compiledParser = expressionsReader( - clauseEvaluatorGenerators, - parserGeneratedSoFar, - detected - ), - - remainingUnparsedJsonPath = jsonPath.substr(len(detected[0])); - - return onSuccess(remainingUnparsedJsonPath, compiledParser); - } - } - - /** - * Partially completes generateClauseReaderIfTokenFound above. - */ - function clauseMatcher(tokenDetector, exprs) { - - return partialComplete( - generateClauseReaderIfTokenFound, - tokenDetector, - exprs - ); - } - - /** - * clauseForJsonPath is a function which attempts to match against - * several clause matchers in order until one matches. If non match the - * jsonPath expression is invalid and an error is thrown. - * - * The parameter list is the same as a single clauseMatcher: - * - * (jsonPath, parserGeneratedSoFar, onSuccess) - */ - var clauseForJsonPath = lazyUnion( - - clauseMatcher(pathNodeSyntax , list( capture, - duckTypeClause, - nameClause, - skip1 )) - - , clauseMatcher(doubleDotSyntax , list( skipMany)) - - // dot is a separator only (like whitespace in other languages) but - // rather than make it a special case, use an empty list of - // expressions when this token is found - , clauseMatcher(dotSyntax , list() ) - - , clauseMatcher(bangSyntax , list( capture, - rootExpr)) - - , clauseMatcher(emptySyntax , list( statementExpr)) - - , function (jsonPath) { - throw Error('"' + jsonPath + '" could not be tokenised') - } - ); - - - /** - * One of two possible values for the onSuccess argument of - * generateClauseReaderIfTokenFound. - * - * When this function is used, generateClauseReaderIfTokenFound simply - * returns the compiledParser that it made, regardless of if there is - * any remaining jsonPath to be compiled. - */ - function returnFoundParser(_remainingJsonPath, compiledParser){ - return compiledParser - } - - /** - * Recursively compile a JSONPath expression. - * - * This function serves as one of two possible values for the onSuccess - * argument of generateClauseReaderIfTokenFound, meaning continue to - * recursively compile. Otherwise, returnFoundParser is given and - * compilation terminates. - */ - function compileJsonPathToFunction( uncompiledJsonPath, - parserGeneratedSoFar ) { - - /** - * On finding a match, if there is remaining text to be compiled - * we want to either continue parsing using a recursive call to - * compileJsonPathToFunction. Otherwise, we want to stop and return - * the parser that we have found so far. - */ - var onFind = uncompiledJsonPath - ? compileJsonPathToFunction - : returnFoundParser; - - return clauseForJsonPath( - uncompiledJsonPath, - parserGeneratedSoFar, - onFind - ); - } - - /** - * This is the function that we expose to the rest of the library. - */ - return function(jsonPath){ - - try { - // Kick off the recursive parsing of the jsonPath - return compileJsonPathToFunction(jsonPath, always); - - } catch( e ) { - throw Error( 'Could not compile "' + jsonPath + - '" because ' + e.message - ); - } - } - -}); - -/** - * A pub/sub which is responsible for a single event type. A - * multi-event type event bus is created by pubSub by collecting - * several of these. - * - * @param {String} eventType - * the name of the events managed by this singleEventPubSub - * @param {singleEventPubSub} [newListener] - * place to notify of new listeners - * @param {singleEventPubSub} [removeListener] - * place to notify of when listeners are removed - */ -function singleEventPubSub(eventType, newListener, removeListener){ - - /** we are optimised for emitting events over firing them. - * As well as the tuple list which stores event ids and - * listeners there is a list with just the listeners which - * can be iterated more quickly when we are emitting - */ - var listenerTupleList, - listenerList; - - function hasId(id){ - return function(tuple) { - return tuple.id == id; - }; - } - - return { - - /** - * @param {Function} listener - * @param {*} listenerId - * an id that this listener can later by removed by. - * Can be of any type, to be compared to other ids using == - */ - on:function( listener, listenerId ) { - - var tuple = { - listener: listener - , id: listenerId || listener // when no id is given use the - // listener function as the id - }; - - if( newListener ) { - newListener.emit(eventType, listener, tuple.id); - } - - listenerTupleList = cons( tuple, listenerTupleList ); - listenerList = cons( listener, listenerList ); - - return this; // chaining - }, - - emit:function () { - applyEach( listenerList, arguments ); - }, - - un: function( listenerId ) { - - var removed; - - listenerTupleList = without( - listenerTupleList, - hasId(listenerId), - function(tuple){ - removed = tuple; - } - ); - - if( removed ) { - listenerList = without( listenerList, function(listener){ - return listener == removed.listener; - }); - - if( removeListener ) { - removeListener.emit(eventType, removed.listener, removed.id); - } - } - }, - - listeners: function(){ - // differs from Node EventEmitter: returns list, not array - return listenerList; - }, - - hasListener: function(listenerId){ - var test = listenerId? hasId(listenerId) : always; - - return defined(first( test, listenerTupleList)); - } - }; -} -/** - * pubSub is a curried interface for listening to and emitting - * events. - * - * If we get a bus: - * - * var bus = pubSub(); - * - * We can listen to event 'foo' like: - * - * bus('foo').on(myCallback) - * - * And emit event foo like: - * - * bus('foo').emit() - * - * or, with a parameter: - * - * bus('foo').emit('bar') - * - * All functions can be cached and don't need to be - * bound. Ie: - * - * var fooEmitter = bus('foo').emit - * fooEmitter('bar'); // emit an event - * fooEmitter('baz'); // emit another - * - * There's also an uncurried[1] shortcut for .emit and .on: - * - * bus.on('foo', callback) - * bus.emit('foo', 'bar') - * - * [1]: http://zvon.org/other/haskell/Outputprelude/uncurry_f.html - */ -function pubSub(){ - - var singles = {}, - newListener = newSingle('newListener'), - removeListener = newSingle('removeListener'); - - function newSingle(eventName) { - return singles[eventName] = singleEventPubSub( - eventName, - newListener, - removeListener - ); - } - - /** pubSub instances are functions */ - function pubSubInstance( eventName ){ - - return singles[eventName] || newSingle( eventName ); - } - - // add convenience EventEmitter-style uncurried form of 'emit' and 'on' - ['emit', 'on', 'un'].forEach(function(methodName){ - - pubSubInstance[methodName] = varArgs(function(eventName, parameters){ - apply( parameters, pubSubInstance( eventName )[methodName]); - }); - }); - - return pubSubInstance; -} - -/** - * This file declares some constants to use as names for event types. - */ - -var // the events which are never exported are kept as - // the smallest possible representation, in numbers: - _S = 1, - - // fired whenever a new node starts in the JSON stream: - NODE_OPENED = _S++, - - // fired whenever a node closes in the JSON stream: - NODE_CLOSED = _S++, - - // called if a .node callback returns a value - - NODE_SWAP = _S++, - NODE_DROP = _S++, - - FAIL_EVENT = 'fail', - - ROOT_NODE_FOUND = _S++, - ROOT_PATH_FOUND = _S++, - - HTTP_START = 'start', - STREAM_DATA = 'data', - STREAM_END = 'end', - ABORTING = _S++, - - // SAX events butchered from Clarinet - SAX_KEY = _S++, - SAX_VALUE_OPEN = _S++, - SAX_VALUE_CLOSE = _S++; - -function errorReport(statusCode, body, error) { - try{ - var jsonBody = JSON.parse(body); - }catch(e){} - - return { - statusCode:statusCode, - body:body, - jsonBody:jsonBody, - thrown:error - }; -} - -/** - * The pattern adaptor listens for newListener and removeListener - * events. When patterns are added or removed it compiles the JSONPath - * and wires them up. - * - * When nodes and paths are found it emits the fully-qualified match - * events with parameters ready to ship to the outside world - */ - -function patternAdapter(oboeBus, jsonPathCompiler) { - - var predicateEventMap = { - node:oboeBus(NODE_CLOSED) - , path:oboeBus(NODE_OPENED) - }; - - function emitMatchingNode(emitMatch, node, ascent) { - - /* - We're now calling to the outside world where Lisp-style - lists will not be familiar. Convert to standard arrays. - - Also, reverse the order because it is more common to - list paths "root to leaf" than "leaf to root" */ - var descent = reverseList(ascent); - - emitMatch( - node, - - // To make a path, strip off the last item which is the special - // ROOT_PATH token for the 'path' to the root node - listAsArray(tail(map(keyOf,descent))), // path - listAsArray(map(nodeOf, descent)) // ancestors - ); - } - - /* - * Set up the catching of events such as NODE_CLOSED and NODE_OPENED and, if - * matching the specified pattern, propagate to pattern-match events such as - * oboeBus('node:!') - * - * - * - * @param {Function} predicateEvent - * either oboeBus(NODE_CLOSED) or oboeBus(NODE_OPENED). - * @param {Function} compiledJsonPath - */ - function addUnderlyingListener( fullEventName, predicateEvent, compiledJsonPath ){ - - var emitMatch = oboeBus(fullEventName).emit; - - predicateEvent.on( function (ascent) { - - var maybeMatchingMapping = compiledJsonPath(ascent); - - /* Possible values for maybeMatchingMapping are now: - - false: - we did not match - - an object/array/string/number/null: - we matched and have the node that matched. - Because nulls are valid json values this can be null. - - undefined: - we matched but don't have the matching node yet. - ie, we know there is an upcoming node that matches but we - can't say anything else about it. - */ - if (maybeMatchingMapping !== false) { - - emitMatchingNode( - emitMatch, - nodeOf(maybeMatchingMapping), - ascent - ); - } - }, fullEventName); - - oboeBus('removeListener').on( function(removedEventName){ - - // if the fully qualified match event listener is later removed, clean up - // by removing the underlying listener if it was the last using that pattern: - - if( removedEventName == fullEventName ) { - - if( !oboeBus(removedEventName).listeners( )) { - predicateEvent.un( fullEventName ); - } - } - }); - } - - oboeBus('newListener').on( function(fullEventName){ - - var match = /(node|path):(.*)/.exec(fullEventName); - - if( match ) { - var predicateEvent = predicateEventMap[match[1]]; - - if( !predicateEvent.hasListener( fullEventName) ) { - - addUnderlyingListener( - fullEventName, - predicateEvent, - jsonPathCompiler( match[2] ) - ); - } - } - }) - -} - -/** - * 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 - */ -function instanceApi(oboeBus, contentSource){ - - var oboeApi, - fullyQualifiedNamePattern = /^(node|path):./, - rootNodeFinishedEvent = oboeBus(ROOT_NODE_FOUND), - emitNodeDrop = oboeBus(NODE_DROP).emit, - emitNodeSwap = oboeBus(NODE_SWAP).emit, - - /** - * 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 - // .event() equivalent with special behaviour , pass through - // 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); - } else { - - // 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 - */ - 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); - } 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); - } - - 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 - * 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 - } - - /** - * Add a callback where, if .forget() is called during the callback's - * 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 ); - - delete oboeApi.forget; - - if( discard ) { - event.un(listenerId); - } - }, listenerId); - - return oboeApi; // chaining - } - - /** - * wrap a callback so that if it throws, Oboe.js doesn't crash but instead - * handles it like a normal error - */ - function protectedCallback( callback ) { - return function() { - 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)); - } - } - } - - /** - * 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); - } - - function wrapCallbackToSwapNodeIfSomethingReturned( callback ) { - return function() { - var returnValueFromCallback = callback.apply(this, arguments); - - if( defined(returnValueFromCallback) ) { - - if( returnValueFromCallback == oboe.drop ) { - emitNodeDrop(); - } else { - emitNodeSwap(returnValueFromCallback); - } - } - } - } - - function addSingleNodeOrPathListener(eventId, pattern, callback) { - - var effectiveCallback; - - if( eventId == 'node' ) { - effectiveCallback = wrapCallbackToSwapNodeIfSomethingReturned(callback); - } else { - effectiveCallback = callback; - } - - addForgettableCallback( - fullyQualifiedPatternMatchEvent(eventId, pattern), - effectiveCallback, - callback - ); - } - - /** - * 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: - oboeBus(ROOT_PATH_FOUND).on( function(rootNode) { - oboeApi.root = functor(rootNode); - }); - - /** - * When content starts make the headers readable through the - * instance API - */ - oboeBus(HTTP_START).on( function(_statusCode, headers) { - - oboeApi.header = function(name) { - return name ? headers[name] - : headers - ; - } - }); - - /** - * Construct and return the public API of the Oboe instance to be - * returned to the calling application - */ - return oboeApi = { - on : addListener, - addListener : addListener, - removeListener : removeListener, - emit : oboeBus.emit, - - node : partialComplete(addNodeOrPathListenerApi, 'node'), - path : partialComplete(addNodeOrPathListenerApi, 'path'), - - done : partialComplete(addForgettableCallback, rootNodeFinishedEvent), - start : partialComplete(addProtectedCallback, HTTP_START ), - - // 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 - * Oboe instance. It creates the new components that are required - * and introduces them to each other. - */ - -function wire (httpMethodName, contentSource, body, headers, withCredentials){ - - var oboeBus = pubSub(); - - // Wire the input stream in if we are given a content source. - // This will usually be the case. If not, the instance created - // will have to be passed content from an external source. - - if( contentSource ) { - - streamingHttp( oboeBus, - httpTransport(), - httpMethodName, - contentSource, - body, - headers, - withCredentials - ); - } - - clarinet(oboeBus); - - ascentManager(oboeBus, incrementalContentBuilder(oboeBus)); - - patternAdapter(oboeBus, jsonPathCompiler); - - return instanceApi(oboeBus, contentSource); -} - -function applyDefaults( passthrough, url, httpMethodName, body, headers, withCredentials, cached ){ - - headers = headers ? - // Shallow-clone the headers array. This allows it to be - // modified without side effects to the caller. We don't - // want to change objects that the user passes in. - JSON.parse(JSON.stringify(headers)) - : {}; - - if( body ) { - if( !isString(body) ) { - - // If the body is not a string, stringify it. This allows objects to - // be given which will be sent as JSON. - body = JSON.stringify(body); - - // Default Content-Type to JSON unless given otherwise. - headers['Content-Type'] = headers['Content-Type'] || 'application/json'; - } - } else { - body = null; - } - - // support cache busting like jQuery.ajax({cache:false}) - function modifiedUrl(baseUrl, cached) { - - if( cached === false ) { - - if( baseUrl.indexOf('?') == -1 ) { - baseUrl += '?'; - } else { - baseUrl += '&'; - } - - baseUrl += '_=' + new Date().getTime(); - } - return baseUrl; - } - - return passthrough( httpMethodName || 'GET', modifiedUrl(url, cached), body, headers, withCredentials || false ); -} - -// export public API -function oboe(arg1) { - - // We use duck-typing to detect if the parameter given is a stream, with the - // below list of parameters. - // Unpipe and unshift would normally be present on a stream but this breaks - // compatibility with Request streams. - // See https://github.com/jimhigson/oboe.js/issues/65 - - var nodeStreamMethodNames = list('resume', 'pause', 'pipe'), - isStream = partialComplete( - hasAllProperties - , nodeStreamMethodNames - ); - - if( arg1 ) { - if (isStream(arg1) || isString(arg1)) { - - // simple version for GETs. Signature is: - // oboe( url ) - // or, under node: - // oboe( readableStream ) - return applyDefaults( - wire, - arg1 // url - ); - - } else { - - // method signature is: - // oboe({method:m, url:u, body:b, headers:{...}}) - - return applyDefaults( - wire, - arg1.url, - arg1.method, - arg1.body, - arg1.headers, - arg1.withCredentials, - arg1.cached - ); - - } - } else { - // wire up a no-AJAX, no-stream Oboe. Will have to have content - // fed in externally and using .emit. - return wire(); - } -} - -/* oboe.drop is a special value. If a node callback returns this value the - parsed node is deleted from the JSON - */ -oboe.drop = function() { - return oboe.drop; -}; - - - if ( typeof define === "function" && define.amd ) { - define( "oboe", [], function () { return oboe; } ); - } else if (typeof exports === 'object') { - module.exports = oboe; - } else { - window.oboe = oboe; - } -})((function(){ - // Access to the window object throws an exception in HTML5 web workers so - // point it to "self" if it runs in a web worker - try { - return window; - } catch (e) { - return self; - } - }()), Object, Array, Error, JSON); diff --git a/lib/oboe-browser.min.js b/lib/oboe-browser.min.js deleted file mode 100644 index 6d8dd72fc..000000000 --- a/lib/oboe-browser.min.js +++ /dev/null @@ -1 +0,0 @@ -!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;e Date: Fri, 11 Nov 2022 15:47:20 +0100 Subject: [PATCH 2/2] fix: self in oboe --- package-lock.json | 230 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 230 insertions(+) create mode 100644 package-lock.json diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 000000000..3602f9178 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,230 @@ +{ + "name": "rn-fetch-blob", + "version": "0.13.0-beta.1", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "rn-fetch-blob", + "version": "0.13.0-beta.1", + "license": "MIT", + "dependencies": { + "base-64": "0.1.0", + "glob": "7.0.6", + "lodash": "^4.17.21", + "oboe": "^2.1.5" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "node_modules/base-64": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/base-64/-/base-64-0.1.0.tgz", + "integrity": "sha512-Y5gU45svrR5tI2Vt/X9GPd3L0HNIKzGu202EjxrXMpuc2V2CiKgemAbUUsqYmZJvPtCXoUKjNZwBJzsNScUbXA==" + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + }, + "node_modules/glob": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.0.6.tgz", + "integrity": "sha512-f8c0rE8JiCxpa52kWPAOa3ZaYEnzofDzCQLCn3Vdk0Z5OVLq3BsRFJI4S4ykpeVW6QMGBUkMeUpoEgWnMTnw5Q==", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.2", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/http-https": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/http-https/-/http-https-1.0.0.tgz", + "integrity": "sha512-o0PWwVCSp3O0wS6FvNr6xfBCHgt0m1tvPLFOCc2iFDKTRAXhB7m8klDf7ErowFH8POa6dVdGatKU5I1YYwzUyg==" + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/oboe": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/oboe/-/oboe-2.1.5.tgz", + "integrity": "sha512-zRFWiF+FoicxEs3jNI/WYUrVEgA7DeET/InK0XQuudGHRg8iIob3cNPrJTKaz4004uaA9Pbe+Dwa8iluhjLZWA==", + "dependencies": { + "http-https": "^1.0.0" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + } + }, + "dependencies": { + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" + }, + "base-64": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/base-64/-/base-64-0.1.0.tgz", + "integrity": "sha512-Y5gU45svrR5tI2Vt/X9GPd3L0HNIKzGu202EjxrXMpuc2V2CiKgemAbUUsqYmZJvPtCXoUKjNZwBJzsNScUbXA==" + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" + }, + "glob": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.0.6.tgz", + "integrity": "sha512-f8c0rE8JiCxpa52kWPAOa3ZaYEnzofDzCQLCn3Vdk0Z5OVLq3BsRFJI4S4ykpeVW6QMGBUkMeUpoEgWnMTnw5Q==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.2", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "http-https": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/http-https/-/http-https-1.0.0.tgz", + "integrity": "sha512-o0PWwVCSp3O0wS6FvNr6xfBCHgt0m1tvPLFOCc2iFDKTRAXhB7m8klDf7ErowFH8POa6dVdGatKU5I1YYwzUyg==" + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "oboe": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/oboe/-/oboe-2.1.5.tgz", + "integrity": "sha512-zRFWiF+FoicxEs3jNI/WYUrVEgA7DeET/InK0XQuudGHRg8iIob3cNPrJTKaz4004uaA9Pbe+Dwa8iluhjLZWA==", + "requires": { + "http-https": "^1.0.0" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "requires": { + "wrappy": "1" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==" + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" + } + } +}