diff --git a/graphql.js b/graphql.js index 7b40b1f..02e42df 100644 --- a/graphql.js +++ b/graphql.js @@ -205,7 +205,7 @@ var path = fragment.replace(fragmentRegexp, function (_, $m) {return $m}) var fragment = that.fragmentPath(fragments, path) if (fragment) { - var pathRegexp = new RegExp(fragmentRegexp.source.replace(/\((.*)\)/, path)) + var pathRegexp = new RegExp(fragmentRegexp.source.replace(/\((.*)\)/, path) + '$') if (fragment.match(pathRegexp)) { throw new Error("Recursive fragment usage detected on " + path + ".") } diff --git a/graphql.min.js b/graphql.min.js index 0b08ce5..e55a6d6 100644 --- a/graphql.min.js +++ b/graphql.min.js @@ -1 +1 @@ -(function(){function __extend(){var extended={},deep=false,i=0,length=arguments.length;if(Object.prototype.toString.call(arguments[0])=="[object Boolean]"){deep=arguments[0];i++}var merge=function(obj){for(var prop in obj){if(Object.prototype.hasOwnProperty.call(obj,prop)){if(deep&&Object.prototype.toString.call(obj[prop])=="[object Object]"){extended[prop]=__extend(true,extended[prop],obj[prop])}else{extended[prop]=obj[prop]}}}};for(;i0&&fragmentRegexp.test(fragment)){that.collectFragments(fragment,fragments).forEach(function(fragment){collectedFragments.unshift(fragment)})}}});return __unique(collectedFragments)};GraphQLClient.prototype.processQuery=function(query,fragments){if(typeof query=="object"&&query.hasOwnProperty("kind")&&query.hasOwnProperty("definitions")){throw new Error("Do not use graphql AST to send requests. Please generate query as string first using `graphql.print(query)`")}var fragmentRegexp=GraphQLClient.FRAGMENT_PATTERN;var collectedFragments=this.collectFragments(query,fragments);query=query.replace(fragmentRegexp,function(_,$m){return"... "+$m.split(".").join(FRAGMENT_SEPERATOR)});return[query].concat(collectedFragments.filter(function(fragment){return!query.match(fragment)})).join("\n")};GraphQLClient.prototype.autoDeclare=function(query,variables){var that=this;var typeMap={string:"String",number:function(value){return value%1===0?"Int":"Float"},boolean:"Boolean"};return query.replace(GraphQLClient.AUTODECLARE_PATTERN,function(){var types=[];for(var key in variables){var value=variables[key];var keyAndType=key.split("!");var mapping=typeMap[typeof value];var mappedType=typeof mapping==="function"?mapping(value):mapping;if(!key.match("!")&&keyAndType[0].match(/_?id/i)){mappedType="ID"}var type=keyAndType[1]||mappedType;if(type){types.push("$"+keyAndType[0]+": "+type+"!")}}types=types.join(", ");return types?"("+types+")":""})};GraphQLClient.prototype.cleanAutoDeclareAnnotations=function(variables){if(!variables)variables={};var newVariables={};for(var key in variables){var value=variables[key];var keyAndType=key.split("!");newVariables[keyAndType[0]]=value}return newVariables};GraphQLClient.prototype.buildFragments=function(fragments){var that=this;fragments=this.flatten(fragments||{});var fragmentObject={};for(var name in fragments){var fragment=fragments[name];if(typeof fragment=="object"){fragmentObject[name]=that.buildFragments(fragment)}else{fragmentObject[name]="\nfragment "+name+" "+fragment}}return fragmentObject};GraphQLClient.prototype.buildQuery=function(query,variables){return this.autoDeclare(this.processQuery(query,this._fragments),variables)};GraphQLClient.prototype.parseType=function(query){var match=query.trim().match(/^(query|mutation|subscription)/);if(!match)return"query";return match[1]};GraphQLClient.prototype.createSenderFunction=function(debug){var that=this;return function(query,originalQuery,type){if(__isTagCall(query)){return that.run(that.ql.apply(that,arguments))}var caller=function(variables,requestOptions){if(!requestOptions)requestOptions={};if(!variables)variables={};var fragmentedQuery=that.buildQuery(query,variables);headers=__extend(that.options.headers||{},requestOptions.headers||{});return new Promise(function(resolve,reject){__request(debug,that.options.method||"post",that.getUrl(),headers,{query:fragmentedQuery,variables:that.cleanAutoDeclareAnnotations(variables)},!!that.options.asJSON,that.options.onRequestError,function(response,status){if(status==200){if(response.errors){reject(response.errors)}else if(response.data){resolve(response.data)}else{resolve(response)}}else{reject(response)}})})};caller.merge=function(mergeName,variables){if(!type){type=that.parseType(query);query=query.trim().replace(/^(query|mutation|subscription)\s*/,"").trim().replace(GraphQLClient.AUTODECLARE_PATTERN,"").trim().replace(/^\{|\}$/g,"")}if(!originalQuery){originalQuery=query}that._transaction[mergeName]=that._transaction[mergeName]||{query:[],mutation:[]};return new Promise(function(resolve){that._transaction[mergeName][type].push({type:type,query:originalQuery,variables:variables,resolver:resolve})})};if(arguments.length>3){return caller.apply(null,Array.prototype.slice.call(arguments,3))}return caller}};GraphQLClient.prototype.commit=function(mergeName){if(!this._transaction[mergeName]){throw new Error("You cannot commit the merge "+mergeName+" without creating it first.")}var that=this;var resolveMap={};var mergedVariables={};var mergedQueries={};Object.keys(this._transaction[mergeName]).forEach(function(method){if(that._transaction[mergeName][method].length===0)return;var subQuery=that._transaction[mergeName][method].map(function(merge){var reqId="merge"+Math.random().toString().split(".")[1].substr(0,6);resolveMap[reqId]=merge.resolver;var query=merge.query.replace(/\$([^\.\,\s\)]*)/g,function(_,m){if(!merge.variables){throw new Error("Unused variable on merge "+mergeName+": $"+m[0])}var matchingKey=Object.keys(merge.variables).filter(function(key){return key===m||key.match(new RegExp("^"+m+"!"))})[0];var variable=reqId+"__"+matchingKey;mergedVariables[method]=mergedVariables[method]||{};mergedVariables[method][variable]=merge.variables[matchingKey];return"$"+variable.split("!")[0]});var alias=query.trim().match(/^[^\(]+\:/);if(!alias){alias=query.replace(/^\{|\}$/gm,"").trim().match(/^[^\(\{]+/)[0]+":"}else{query=query.replace(/^[^\(]+\:/,"")}return reqId+"_"+alias+query}).join("\n");mergedQueries[method]=mergedQueries[method]||[];mergedQueries[method].push(method+" (@autodeclare) {\n"+subQuery+"\n }")});return Promise.all(Object.keys(mergedQueries).map(function(method){var query=mergedQueries[method].join("\n");var variables=mergedVariables[method];return that._sender(query,query,null,variables)})).then(function(responses){var newResponses={};responses.forEach(function(response){Object.keys(response).forEach(function(mergeKey){var parsedKey=mergeKey.match(/^(merge\d+)\_(.*)/);if(!parsedKey){throw new Error("Multiple root keys detected on response. Merging doesn't support it yet.")}var reqId=parsedKey[1];var fieldName=parsedKey[2];var newResponse={};newResponse[fieldName]=response[mergeKey];newResponses[fieldName]=(newResponses[fieldName]||[]).concat([response[mergeKey]]);resolveMap[reqId](newResponse)})});return newResponses}).catch(function(responses){return{error:true,errors:responses}}).finally(function(responses){that._transaction[mergeName]={query:[],mutation:[]};return responses})};GraphQLClient.prototype.createHelpers=function(sender){var that=this;function helper(query){if(__isTagCall(query)){that.__prefix=this.prefix;that.__suffix=this.suffix;var result=that.run(that.ql.apply(that,arguments));that.__prefix="";that.__suffix="";return result}var caller=sender(this.prefix+" "+query+" "+this.suffix,query.trim(),this.type);if(arguments.length>1&&arguments[1]!=null){return caller.apply(null,Array.prototype.slice.call(arguments,1))}return caller}var helpers=[{method:"mutate",type:"mutation"},{method:"query",type:"query"},{method:"subscribe",type:"subscription"}];helpers.forEach(function(m){that[m.method]=function(query,variables,options){if(that.options.alwaysAutodeclare===true||options&&options.declare===true){return helper.call({type:m.type,prefix:m.type+" (@autodeclare) {",suffix:"}"},query,variables)}return helper.call({type:m.type,prefix:m.type,suffix:""},query,variables)};that[m.method].run=function(query,options){return that[m.method](query,options)({})}});this.run=function(query){return sender(query,originalQuery,m.type,{})}};GraphQLClient.prototype.fragments=function(){return this._fragments};GraphQLClient.prototype.getOptions=function(){return this.options||{}};GraphQLClient.prototype.headers=function(newHeaders){return this.options.headers=__extend(this.options.headers,newHeaders)};GraphQLClient.prototype.fragment=function(fragment){if(typeof fragment=="string"){var _fragment=this._fragments[fragment.replace(/\./g,FRAGMENT_SEPERATOR)];if(!_fragment){throw"Fragment "+fragment+" not found!"}return _fragment.trim()}else{this.options.fragments=__extend(true,this.options.fragments,fragment);this._fragments=this.buildFragments(this.options.fragments);return this._fragments}};GraphQLClient.prototype.ql=function(strings){var that=this;fragments=Array.prototype.slice.call(arguments,1);fragments=fragments.map(function(fragment){if(typeof fragment=="string"){return fragment.match(/fragment\s+([^\s]*)\s/)[1]}});var query=typeof strings=="string"?strings:strings.reduce(function(acc,seg,i){return acc+fragments[i-1]+seg});query=this.buildQuery(query);query=((this.__prefix||"")+" "+query+" "+(this.__suffix||"")).trim();return query};(function(root,factory){if(typeof define==="function"&&define.amd){define(function(){return root.graphql=factory(GraphQLClient)})}else if(typeof module==="object"&&module.exports){module.exports=factory(root.GraphQLClient)}else{root.graphql=factory(root.GraphQLClient)}})(this,function(){return GraphQLClient})})(); \ No newline at end of file +(function(){function __extend(){var extended={},deep=false,i=0,length=arguments.length;if(Object.prototype.toString.call(arguments[0])=="[object Boolean]"){deep=arguments[0];i++}var merge=function(obj){for(var prop in obj){if(Object.prototype.hasOwnProperty.call(obj,prop)){if(deep&&Object.prototype.toString.call(obj[prop])=="[object Object]"){extended[prop]=__extend(true,extended[prop],obj[prop])}else{extended[prop]=obj[prop]}}}};for(;i0&&fragmentRegexp.test(fragment)){that.collectFragments(fragment,fragments).forEach(function(fragment){collectedFragments.unshift(fragment)})}}});return __unique(collectedFragments)};GraphQLClient.prototype.processQuery=function(query,fragments){if(typeof query=="object"&&query.hasOwnProperty("kind")&&query.hasOwnProperty("definitions")){throw new Error("Do not use graphql AST to send requests. Please generate query as string first using `graphql.print(query)`")}var fragmentRegexp=GraphQLClient.FRAGMENT_PATTERN;var collectedFragments=this.collectFragments(query,fragments);query=query.replace(fragmentRegexp,function(_,$m){return"... "+$m.split(".").join(FRAGMENT_SEPERATOR)});return[query].concat(collectedFragments.filter(function(fragment){return!query.match(fragment)})).join("\n")};GraphQLClient.prototype.autoDeclare=function(query,variables){var that=this;var typeMap={string:"String",number:function(value){return value%1===0?"Int":"Float"},boolean:"Boolean"};return query.replace(GraphQLClient.AUTODECLARE_PATTERN,function(){var types=[];for(var key in variables){var value=variables[key];var keyAndType=key.split("!");var mapping=typeMap[typeof value];var mappedType=typeof mapping==="function"?mapping(value):mapping;if(!key.match("!")&&keyAndType[0].match(/_?id/i)){mappedType="ID"}var type=keyAndType[1]||mappedType;if(type){types.push("$"+keyAndType[0]+": "+type+"!")}}types=types.join(", ");return types?"("+types+")":""})};GraphQLClient.prototype.cleanAutoDeclareAnnotations=function(variables){if(!variables)variables={};var newVariables={};for(var key in variables){var value=variables[key];var keyAndType=key.split("!");newVariables[keyAndType[0]]=value}return newVariables};GraphQLClient.prototype.buildFragments=function(fragments){var that=this;fragments=this.flatten(fragments||{});var fragmentObject={};for(var name in fragments){var fragment=fragments[name];if(typeof fragment=="object"){fragmentObject[name]=that.buildFragments(fragment)}else{fragmentObject[name]="\nfragment "+name+" "+fragment}}return fragmentObject};GraphQLClient.prototype.buildQuery=function(query,variables){return this.autoDeclare(this.processQuery(query,this._fragments),variables)};GraphQLClient.prototype.parseType=function(query){var match=query.trim().match(/^(query|mutation|subscription)/);if(!match)return"query";return match[1]};GraphQLClient.prototype.createSenderFunction=function(debug){var that=this;return function(query,originalQuery,type){if(__isTagCall(query)){return that.run(that.ql.apply(that,arguments))}var caller=function(variables,requestOptions){if(!requestOptions)requestOptions={};if(!variables)variables={};var fragmentedQuery=that.buildQuery(query,variables);headers=__extend(that.options.headers||{},requestOptions.headers||{});return new Promise(function(resolve,reject){__request(debug,that.options.method||"post",that.getUrl(),headers,{query:fragmentedQuery,variables:that.cleanAutoDeclareAnnotations(variables)},!!that.options.asJSON,that.options.onRequestError,function(response,status){if(status==200){if(response.errors){reject(response.errors)}else if(response.data){resolve(response.data)}else{resolve(response)}}else{reject(response)}})})};caller.merge=function(mergeName,variables){if(!type){type=that.parseType(query);query=query.trim().replace(/^(query|mutation|subscription)\s*/,"").trim().replace(GraphQLClient.AUTODECLARE_PATTERN,"").trim().replace(/^\{|\}$/g,"")}if(!originalQuery){originalQuery=query}that._transaction[mergeName]=that._transaction[mergeName]||{query:[],mutation:[]};return new Promise(function(resolve){that._transaction[mergeName][type].push({type:type,query:originalQuery,variables:variables,resolver:resolve})})};if(arguments.length>3){return caller.apply(null,Array.prototype.slice.call(arguments,3))}return caller}};GraphQLClient.prototype.commit=function(mergeName){if(!this._transaction[mergeName]){throw new Error("You cannot commit the merge "+mergeName+" without creating it first.")}var that=this;var resolveMap={};var mergedVariables={};var mergedQueries={};Object.keys(this._transaction[mergeName]).forEach(function(method){if(that._transaction[mergeName][method].length===0)return;var subQuery=that._transaction[mergeName][method].map(function(merge){var reqId="merge"+Math.random().toString().split(".")[1].substr(0,6);resolveMap[reqId]=merge.resolver;var query=merge.query.replace(/\$([^\.\,\s\)]*)/g,function(_,m){if(!merge.variables){throw new Error("Unused variable on merge "+mergeName+": $"+m[0])}var matchingKey=Object.keys(merge.variables).filter(function(key){return key===m||key.match(new RegExp("^"+m+"!"))})[0];var variable=reqId+"__"+matchingKey;mergedVariables[method]=mergedVariables[method]||{};mergedVariables[method][variable]=merge.variables[matchingKey];return"$"+variable.split("!")[0]});var alias=query.trim().match(/^[^\(]+\:/);if(!alias){alias=query.replace(/^\{|\}$/gm,"").trim().match(/^[^\(\{]+/)[0]+":"}else{query=query.replace(/^[^\(]+\:/,"")}return reqId+"_"+alias+query}).join("\n");mergedQueries[method]=mergedQueries[method]||[];mergedQueries[method].push(method+" (@autodeclare) {\n"+subQuery+"\n }")});return Promise.all(Object.keys(mergedQueries).map(function(method){var query=mergedQueries[method].join("\n");var variables=mergedVariables[method];return that._sender(query,query,null,variables)})).then(function(responses){var newResponses={};responses.forEach(function(response){Object.keys(response).forEach(function(mergeKey){var parsedKey=mergeKey.match(/^(merge\d+)\_(.*)/);if(!parsedKey){throw new Error("Multiple root keys detected on response. Merging doesn't support it yet.")}var reqId=parsedKey[1];var fieldName=parsedKey[2];var newResponse={};newResponse[fieldName]=response[mergeKey];newResponses[fieldName]=(newResponses[fieldName]||[]).concat([response[mergeKey]]);resolveMap[reqId](newResponse)})});return newResponses}).catch(function(responses){return{error:true,errors:responses}}).finally(function(responses){that._transaction[mergeName]={query:[],mutation:[]};return responses})};GraphQLClient.prototype.createHelpers=function(sender){var that=this;function helper(query){if(__isTagCall(query)){that.__prefix=this.prefix;that.__suffix=this.suffix;var result=that.run(that.ql.apply(that,arguments));that.__prefix="";that.__suffix="";return result}var caller=sender(this.prefix+" "+query+" "+this.suffix,query.trim(),this.type);if(arguments.length>1&&arguments[1]!=null){return caller.apply(null,Array.prototype.slice.call(arguments,1))}return caller}var helpers=[{method:"mutate",type:"mutation"},{method:"query",type:"query"},{method:"subscribe",type:"subscription"}];helpers.forEach(function(m){that[m.method]=function(query,variables,options){if(that.options.alwaysAutodeclare===true||options&&options.declare===true){return helper.call({type:m.type,prefix:m.type+" (@autodeclare) {",suffix:"}"},query,variables)}return helper.call({type:m.type,prefix:m.type,suffix:""},query,variables)};that[m.method].run=function(query,options){return that[m.method](query,options)({})}});this.run=function(query){return sender(query,originalQuery,m.type,{})}};GraphQLClient.prototype.fragments=function(){return this._fragments};GraphQLClient.prototype.getOptions=function(){return this.options||{}};GraphQLClient.prototype.headers=function(newHeaders){return this.options.headers=__extend(this.options.headers,newHeaders)};GraphQLClient.prototype.fragment=function(fragment){if(typeof fragment=="string"){var _fragment=this._fragments[fragment.replace(/\./g,FRAGMENT_SEPERATOR)];if(!_fragment){throw"Fragment "+fragment+" not found!"}return _fragment.trim()}else{this.options.fragments=__extend(true,this.options.fragments,fragment);this._fragments=this.buildFragments(this.options.fragments);return this._fragments}};GraphQLClient.prototype.ql=function(strings){var that=this;fragments=Array.prototype.slice.call(arguments,1);fragments=fragments.map(function(fragment){if(typeof fragment=="string"){return fragment.match(/fragment\s+([^\s]*)\s/)[1]}});var query=typeof strings=="string"?strings:strings.reduce(function(acc,seg,i){return acc+fragments[i-1]+seg});query=this.buildQuery(query);query=((this.__prefix||"")+" "+query+" "+(this.__suffix||"")).trim();return query};(function(root,factory){if(typeof define==="function"&&define.amd){define(function(){return root.graphql=factory(GraphQLClient)})}else if(typeof module==="object"&&module.exports){module.exports=factory(root.GraphQLClient)}else{root.graphql=factory(root.GraphQLClient)}})(this,function(){return GraphQLClient})})(); \ No newline at end of file