@singularityql/resolver
Version:
SingularityQL resolver for parsing SingularityQL queries and generating a response
3 lines (2 loc) • 6.76 kB
JavaScript
;var __defProp=Object.defineProperty;var __getOwnPropDesc=Object.getOwnPropertyDescriptor;var __getOwnPropNames=Object.getOwnPropertyNames;var __hasOwnProp=Object.prototype.hasOwnProperty;var __export=(target,all)=>{for(var name in all)__defProp(target,name,{get:all[name],enumerable:true})};var __copyProps=(to,from,except,desc)=>{if(from&&typeof from==="object"||typeof from==="function"){for(let key of __getOwnPropNames(from))if(!__hasOwnProp.call(to,key)&&key!==except)__defProp(to,key,{get:()=>from[key],enumerable:!(desc=__getOwnPropDesc(from,key))||desc.enumerable})}return to};var __toCommonJS=mod=>__copyProps(__defProp({},"__esModule",{value:true}),mod);var index_exports={};__export(index_exports,{addResolver:()=>addResolver,resolve:()=>resolve});module.exports=__toCommonJS(index_exports);function tokenTypeToString(tokenType){switch(tokenType){case 0:return"Identifier";case 1:return"BraceLeft";case 2:return"BraceRight";case 3:return"ParenthesesLeft";case 4:return"ParenthesesRight";case 5:return"StringLiteral";case 6:return"NumberLiteral";case 7:return"Comma";case 8:return"Colon";case 9:return"QuestionMark";default:return"UnknownToken"}}function tokenize(query){const tokens=[];let line=1;let position=0;let buffer="";let inString=false;const pushToken=(type,value)=>{if(value.length<1){return}tokens.push({line,position,type,value});position+=value.length};const pushBuffer=()=>{if(buffer.length<1)return;if(/^[0-9]+(\.[0-9]+)?$/.test(buffer)){pushToken(6,buffer)}else{pushToken(0,buffer)}buffer=""};for(let i=0;i<query.length;i++){const currentChar=query[i];if(!inString){if(currentChar=="\n"){pushBuffer();line++;position=0;continue}if(currentChar==" "||currentChar==" "||currentChar=="\r"){pushBuffer();position++;continue}switch(currentChar){case"{":pushBuffer();pushToken(1,"{");continue;case"}":pushBuffer();pushToken(2,"}");continue;case"(":pushBuffer();pushToken(3,"(");continue;case")":pushBuffer();pushToken(4,")");continue;case",":pushBuffer();pushToken(7,",");continue;case":":pushBuffer();pushToken(8,":");continue;case"?":pushBuffer();pushToken(9,"?");continue;case'"':pushBuffer();inString=true;position++;continue}}else if(currentChar=='"'){pushToken(5,buffer);buffer="";inString=false;position++;continue}buffer+=currentChar}pushBuffer();return tokens}var TokenStream=class{tokens;position;constructor(tokens){this.tokens=tokens;this.position=-1}getCurrent(){return this.tokens[this.position]}advance(...expectedTokenTypes){let nextToken=this.peek();if(expectedTokenTypes.find(tokenType=>tokenType==nextToken.type)===void 0){throw new Error(`Unexpected token ${tokenTypeToString(nextToken.type)} at ${nextToken.line}:${nextToken.position}`)}return this.advanceAny()}advanceAny(){if(!this.peek())return void 0;this.position++;return this.getCurrent()}peek(){const nextToken=this.tokens[this.position+1];if(!nextToken){let current=this.getCurrent();throw new Error(`Unexpected end of stream at ${current.line}:${current.position}`)}return nextToken}peekAny(){return this.tokens[this.position+1]||void 0}};function parse(query){const queries=[];const tokenStream=new TokenStream(tokenize(query));while(true){queries.push(parseQuery(tokenStream));if(!tokenStream.peekAny())break}return queries}function parseQuery(stream){const resolverNameToken=stream.advance(0);const params=parseParams(stream);const requestedData=parseRequestedData(stream);const alias=parseAlias(stream);return{resolverName:resolverNameToken.value,params,requestedData,alias}}function parseParams(stream){let params=[];stream.advance(3);if(stream.peek().type!=4){while(true){let paramType;let token=stream.advance(0,5,6,8);if(token.type==8){paramType=4;token=stream.advance(0)}else{switch(token.type){case 0:if(token.value=="true"||token.value=="false"){paramType=1}else{paramType=0}break;case 5:paramType=2;break;case 6:paramType=3;break}}if(paramType==void 0){throw new Error(`Failed to parse parameter type at ${token.line}:${token.position}`)}params.push({type:paramType,value:token.value});if(stream.peek().type!==7)break;stream.advance(7)}}stream.advance(4);return params}function parseRequestedData(stream){const requestedData=[];stream.advance(1);if(stream.peek().type!=2){while(true){const token=stream.advance(0);let optional=false;if(stream.peek().type==9){stream.advanceAny();optional=true}const alias=parseAlias(stream);requestedData.push({value:token.value,alias,optional});if(stream.peek().type!==7)break;stream.advance(7)}}stream.advance(2);return requestedData}function parseAlias(stream){let next=stream.peekAny();if(!next||next.type!=0||next.value!="as"){return}stream.advance(0);return stream.advance(0).value}var resolvers=new Map;var RESERVED_KEYWORDS=["status","error"];function addResolver(name,handler){if(RESERVED_KEYWORDS.find(keyword=>keyword==name)){throw new Error(`Cannot create resolver \`${name}\` because it is a reserved keyword in SingularityQL`)}if(resolvers.get(name)){throw new Error(`Resolver for \`${name}\` already exists`)}resolvers.set(name,handler)}async function resolve(queryStr,placeholders){const output={status:0};try{const queries=parse(queryStr);const queryScopedVariables={};for(let i=0;i<queries.length;i++){const query=queries[i];const resolver=resolvers.get(query.resolverName);const queryResult={};if(!resolver)throw new Error(`Unknown resolver \`${query.resolverName}\``);const resolved=await resolver(...query.params.map(param=>{if(param.type==2){return param.value}else if(param.type==1){return param.value=="true"?true:false}else if(param.type==3){let result=Number(param.value);if(Number.isNaN(result))throw new Error("Failed to parse Number");return result}else if(param.type==4){let result=placeholders[param.value];if(result==void 0)throw new Error(`Placeholder \`${param.value}\` was not passed`);return result}else if(param.type==0){let result=queryScopedVariables[param.value];if(result==void 0)throw new Error(`Query-scoped variable \`${param.value}\` does not exist`);return result}throw new Error("Unknown query parameter type")}));for(let j=0;j<query.requestedData.length;j++){const dataRequest=query.requestedData[j];const value=resolved[dataRequest.value];if(!value&&!dataRequest.optional)throw new Error(`Value \`${dataRequest.value}\` was requested but not returned by the resolver`);queryResult[dataRequest.alias||dataRequest.value]=value;queryScopedVariables[dataRequest.alias||dataRequest.value]=value}const targetQueryName=query.alias||query.resolverName;if(output[targetQueryName]){throw new Error(`Query name \`${targetQueryName}\` is ambiguous`)}output[targetQueryName]=queryResult}output.status=1;return output}catch(err){output.status=2;output.error=err.toString()}return output}0&&(module.exports={addResolver,resolve});
//# sourceMappingURL=index.js.map