├── .bowerrc ├── .gitignore ├── .nvmrc ├── .travis.yml ├── LICENSE ├── README.md ├── bower.json ├── depmonkey.ignore ├── example └── simple.js ├── package-lock.json ├── package.json ├── pom.xml ├── src └── GraphQlQuery.ts ├── test └── GraphQlQuery.spec.ts ├── tsconfig.json ├── typings.json ├── typings ├── globals │ └── mocha │ │ ├── index.d.ts │ │ └── typings.json └── index.d.ts ├── wallaby.js └── wix-graphql-query-builder.iml /.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "registry": { 3 | "search": ["https://bower.herokuapp.com", "http://wix:wix@mirror.wixpress.com:3333"], 4 | "register": "http://wix:wix@mirror.wixpress.com:3333", 5 | "publish": "http://wix:wix@mirror.wixpress.com:3333" 6 | }, 7 | "directory": "app/bower_components" 8 | } 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # OS or Editor folders 2 | .DS_Store 3 | .cache 4 | .project 5 | .settings 6 | nbproject 7 | thumbs.db 8 | 9 | # Komodo 10 | *.komodoproject 11 | .komodotools 12 | 13 | # Folders to ignore 14 | node_modules 15 | coverage 16 | .idea/ 17 | dist/ 18 | typings/ 19 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 8 2 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "6.0.0" 4 | # https://strongloop.com/strongblog/npm-modules-travis-coveralls/ 5 | script: npm run-script test-travis 6 | # Send coverage data to Coveralls 7 | after_success: "cat ./coverage/lcov.info | ./node_modules/coveralls/bin/coveralls.js" -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Brian Shannon 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # graphql-query-builder 2 | 3 | a simple but powerful graphQL query builder 4 | 5 | # Install 6 | 7 | `npm install wix-graphql-query-builder` 8 | 9 | `bower install graphql-query-builder` 10 | 11 | # Example 12 | 13 | ``` js 14 | var Query = require('graphql-query-builder'); 15 | 16 | // example of nesting Querys 17 | /* 18 | { 19 | user( id:3500401 ) { 20 | id, 21 | nickname : name, 22 | isViewerFriend, 23 | 24 | image: profilePicture( size:50 ) { 25 | uri, 26 | width, 27 | height 28 | } 29 | } 30 | } 31 | */ 32 | 33 | let profilePicture = new GraphQlQuery('profilePicture', {size: 50}) 34 | .select('uri', 'width', 'height'); 35 | 36 | let user = new GraphQlQuery('user', {id: 3500401}) 37 | .select('id', {'nickname': 'name'}, 'isViewerFriend', {'image': profilePicture}); 38 | 39 | 40 | console.log('user', user.toString()); 41 | 42 | ``` -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "graphql-query-builder", 3 | "main": "index.js", 4 | "version": "1.0.0", 5 | "homepage": "https://github.com/wix/graphql-query-builder", 6 | "authors": [ 7 | "danielagreen " 8 | ], 9 | "description": "graphql query builder", 10 | "license": "MIT", 11 | "ignore": [ 12 | "**/.*", 13 | "node_modules", 14 | "bower_components", 15 | "app/bower_components", 16 | "test", 17 | "tests" 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /depmonkey.ignore: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /example/simple.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var GraphQlQuery = require('../dist/src/GraphQlQuery'); 4 | 5 | 6 | /* 7 | { 8 | user( id:3500401 ) { 9 | id, 10 | nickname : name, 11 | isViewerFriend, 12 | 13 | image: profilePicture( size:50 ) { 14 | uri, 15 | width, 16 | height 17 | } 18 | } 19 | } 20 | */ 21 | 22 | let profilePicture = new GraphQlQuery('profilePicture', {size: 50}) 23 | .select('uri', 'width', 'height'); 24 | 25 | let user = new GraphQlQuery('user', {id: 3500401}) 26 | .select('id', {'nickname': 'name'}, 'isViewerFriend', {'image': profilePicture}); 27 | 28 | 29 | console.log('user', user.toString()); 30 | /* 31 | 32 | query FetchLeeAndSam { 33 | lee: user(id: "1") { 34 | name 35 | } 36 | sam: user(id: "2") { 37 | name 38 | } 39 | } 40 | */ 41 | 42 | let FetchLeeAndSam = new GraphQlQuery('FetchLeeAndSam'); 43 | 44 | let lee = new GraphQlQuery({lee: 'user'}, {id: '1'}); 45 | lee.select('name'); 46 | 47 | console.log('lee', lee.toString()); 48 | 49 | let sam = new GraphQlQuery({sam: 'user'}, {id: '2'}); 50 | sam.select('name'); 51 | console.log('sam', sam + ''); 52 | 53 | console.log(lee.join(sam).toString()); 54 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "wix-graphql-query-builder", 3 | "version": "1.0.1", 4 | "description": "a simple but powerful graphQL query builder", 5 | "bin": {}, 6 | "files": [ 7 | "dist" 8 | ], 9 | "dependencies": {}, 10 | "devDependencies": { 11 | "@types/node": "^10.5.2", 12 | "bower": "^1.7.9", 13 | "bower-auto-release": "^1.0.99", 14 | "chai": "^3.5.0", 15 | "coveralls": "^2.11.11", 16 | "istanbul": "^0.4.4", 17 | "mocha": "^2.5.3", 18 | "typescript": "^2.5.2", 19 | "yoshi": "latest" 20 | }, 21 | "scripts": { 22 | "build": ":", 23 | "pretest": "yoshi build", 24 | "test": "npm run test:unit", 25 | "test:unit": "yoshi test --mocha", 26 | "release": "yoshi release; bower-auto-release --dist dist/src" 27 | }, 28 | "repository": { 29 | "type": "git", 30 | "url": "git://github.com/wix/graphql-query-builder.git" 31 | }, 32 | "homepage": "https://github.com/wix/graphql-query-builder", 33 | "keywords": [ 34 | "graphql", 35 | "query", 36 | "builder", 37 | "generator", 38 | "orm" 39 | ], 40 | "author": { 41 | "name": "Brian Shannon", 42 | "url": "https://github.com/codemeasandwich/" 43 | }, 44 | "license": "MIT", 45 | "bugs": { 46 | "url": "https://github.com/codemeasandwich/graphql-query-builder/issues" 47 | }, 48 | "private": false, 49 | "publishConfig": { 50 | "registry": "http://repo.dev.wix/artifactory/api/npm/npm-local/" 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | com.wixpress.npm 6 | wix-graphql-query-builder 7 | pom 8 | wix-graphql-query-builder 9 | 10 | 1.0.0-SNAPSHOT 11 | 12 | 13 | Daniela Green 14 | danielagr@wix.com 15 | 16 | owner 17 | 18 | 19 | 20 | Nachshon Schwartz 21 | nachshons@wix.com 22 | 23 | developer 24 | 25 | 26 | 27 | Ronny Ringel 28 | ronnyr@wix.com 29 | 30 | developer 31 | 32 | 33 | 34 | 35 | com.wixpress.common 36 | wix-master-parent 37 | 100.0.0-SNAPSHOT 38 | 39 | 40 | -------------------------------------------------------------------------------- /src/GraphQlQuery.ts: -------------------------------------------------------------------------------- 1 | namespace gql { 2 | export interface GraphQlQueryFactory { 3 | new (fnName: string | IAlias, argumentsMap?: IArgumentsMap): GraphQlQuery; 4 | } 5 | 6 | export interface IArgumentsMap { 7 | [index: string]: string|number|boolean|Object|EnumValue; 8 | } 9 | 10 | export interface IAlias { 11 | [index: string]: string | GraphQlQuery; 12 | } 13 | 14 | export interface IHead { 15 | fnName: IAlias; 16 | argumentsMap?: IArgumentsMap; 17 | } 18 | 19 | export interface IBody { 20 | attr: IAlias; 21 | argumentsMap?: IArgumentsMap; 22 | } 23 | 24 | export interface ISelection extends IArgumentsMap { 25 | _filter?: Object; 26 | } 27 | 28 | export class GraphQlQuery { 29 | private head: IHead; 30 | private body: (IBody|GraphQlQuery)[]; 31 | private isContainer: boolean; 32 | private isWithoutBody: boolean; 33 | 34 | constructor(fnName: string | IAlias, argumentsMap: IArgumentsMap = {}) { 35 | this.head = typeof fnName === 'string' ? {fnName: {[fnName]: fnName}} : {fnName}; 36 | this.head.argumentsMap = argumentsMap; 37 | this.body = []; 38 | this.isContainer = false; 39 | this.isWithoutBody = false; 40 | } 41 | 42 | public select(...selects: (string | ISelection | GraphQlQuery)[]): GraphQlQuery { 43 | if (this.isContainer) { 44 | throw new Error('Can`t use selection on joined query.'); 45 | } 46 | 47 | this.body = this.body.concat(selects.map((item) => { 48 | let selection: any = {}; 49 | 50 | if (typeof item === 'string') { 51 | selection.attr = {[item]: item}; 52 | selection.argumentsMap = {}; 53 | } else if (item instanceof GraphQlQuery) { 54 | selection = item; 55 | } else if (typeof item === 'object') { 56 | selection.argumentsMap = item['_filter'] || {}; 57 | delete item['_filter']; 58 | selection.attr = item; 59 | } 60 | 61 | return selection; 62 | })); 63 | return this; 64 | } 65 | 66 | public filter(argumentsMap: IArgumentsMap): GraphQlQuery { 67 | for (let key in argumentsMap) { 68 | if (argumentsMap.hasOwnProperty(key)) { 69 | this.head.argumentsMap[key] = argumentsMap[key]; 70 | } 71 | } 72 | 73 | return this; 74 | } 75 | 76 | public join(...queries: GraphQlQuery[]): GraphQlQuery { 77 | const combined = new GraphQlQuery(''); 78 | combined.isContainer = true; 79 | combined.body.push(this); 80 | combined.body = combined.body.concat(queries); 81 | 82 | return combined; 83 | } 84 | 85 | public withoutBody(): GraphQlQuery { 86 | if (this.isContainer) { 87 | throw new Error('Can`t use withoutBody on joined query.'); 88 | } 89 | 90 | this.isWithoutBody = true; 91 | return this; 92 | } 93 | 94 | public toString() { 95 | if (this.isContainer) { 96 | return `{ ${this.buildBody()} }`; 97 | } else if (this.isWithoutBody) { 98 | return `{ ${this.buildHeader()} }`; 99 | } else { 100 | return `{ ${this.buildHeader()}{${this.buildBody()}} }`; 101 | } 102 | } 103 | 104 | private buildHeader(): string { 105 | return this.buildAlias(this.head.fnName) + this.buildArguments(this.head.argumentsMap); 106 | } 107 | 108 | private buildArguments(argumentsMap: IArgumentsMap): string { 109 | const query = this.objectToString(argumentsMap); 110 | 111 | return query ? `(${query})` : ''; 112 | } 113 | 114 | private getGraphQLValue(value): string { 115 | if (Array.isArray(value)) { 116 | const arrayString = value.map(item => { 117 | return this.getGraphQLValue(item); 118 | }).join(); 119 | 120 | return `[${arrayString}]`; 121 | } else if (value instanceof EnumValue) { 122 | return value.toString(); 123 | } else if ("object" === typeof value) { 124 | return '{' + this.objectToString(value) + '}'; 125 | } else { 126 | return JSON.stringify(value); 127 | } 128 | } 129 | 130 | private objectToString(obj): string { 131 | return Object.keys(obj).map((key) => `${key}: ${this.getGraphQLValue(obj[key])}`).join(', '); 132 | } 133 | 134 | private buildAlias(attr: IAlias): string { 135 | let alias = Object.keys(attr)[0]; 136 | let value = this.prepareAsInnerQuery(attr[alias]); 137 | 138 | value = (alias !== value) ? `${alias}: ${value}` : value; 139 | return value; 140 | } 141 | 142 | private buildBody(): string { 143 | return this.body.map((item: IBody | GraphQlQuery) => { 144 | if (item instanceof GraphQlQuery) { 145 | return this.prepareAsInnerQuery(item); 146 | } else { 147 | return this.buildAlias(item['attr']) + this.buildArguments(item['argumentsMap']); 148 | } 149 | }).join(' '); 150 | } 151 | 152 | private prepareAsInnerQuery(query: string|GraphQlQuery): string { 153 | let ret = ''; 154 | if (query instanceof GraphQlQuery) { 155 | ret = query.toString(); 156 | ret = ret.substr(2, ret.length - 4); 157 | } else { 158 | ret = query.toString(); 159 | } 160 | return ret; 161 | } 162 | } 163 | 164 | export class EnumValue { 165 | private value: string; 166 | 167 | constructor(value: string) { 168 | this.value = value; 169 | } 170 | 171 | public toString(): string { 172 | return this.value; 173 | } 174 | } 175 | 176 | export function enumValue(value: string): EnumValue { 177 | return new EnumValue(value); 178 | } 179 | } 180 | 181 | if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') { 182 | module.exports = { 183 | GraphQlQuery: gql.GraphQlQuery, 184 | EnumValue: gql.EnumValue, 185 | enumValue: gql.enumValue 186 | } 187 | } 188 | -------------------------------------------------------------------------------- /test/GraphQlQuery.spec.ts: -------------------------------------------------------------------------------- 1 | describe('GraphQL Query Builder', () => { 2 | const expect = require('chai').expect; 3 | const { GraphQlQuery, enumValue } : { GraphQlQuery: gql.GraphQlQueryFactory, enumValue: (string) => gql.EnumValue } = require('../src/GraphQlQuery'); 4 | 5 | describe('product', () => { 6 | it('should include product', () => { 7 | const query = new GraphQlQuery('product'); 8 | expect(query.toString()).to.equal('{ product{} }'); 9 | }); 10 | 11 | it('should support alias for product', () => { 12 | const query = new GraphQlQuery({alias: 'product'}); 13 | expect(query.toString()).to.equal('{ alias: product{} }'); 14 | }); 15 | 16 | it('should support arguments for product', () => { 17 | const query = new GraphQlQuery({alias: 'product'}, {attr1: 'value1', attr2: 2, attr3: true}); 18 | expect(query.toString()).to.equal('{ alias: product(attr1: "value1", attr2: 2, attr3: true){} }'); 19 | }); 20 | 21 | it('should support nested filtering', () => { 22 | const query = new GraphQlQuery('product', {attr1: {attr2: {attr3: {attr4: 'val'}}}}); 23 | expect(query.toString()).to.equal('{ product(attr1: {attr2: {attr3: {attr4: "val"}}}){} }'); 24 | }); 25 | 26 | it('should handle empty arguments', () => { 27 | const query = new GraphQlQuery('product', {}); 28 | expect(query.toString()).to.equal('{ product{} }'); 29 | }); 30 | }); 31 | 32 | describe('enum value', () => { 33 | it('should return value set on toString', () => { 34 | const type = 'text'; 35 | expect(enumValue(type).toString()).to.equal(type); 36 | }); 37 | 38 | it('should filter without quotes', () => { 39 | const query = new GraphQlQuery('domain').filter({key: enumValue('value')}); 40 | expect(query.toString()).to.equal('{ domain(key: value){} }'); 41 | }); 42 | 43 | //TODO test nested 44 | }); 45 | 46 | describe('filter', () => { 47 | it('should support filter product', () => { 48 | const query = new GraphQlQuery('product'); 49 | query.filter({attr1: 'value1', attr2: 2, attr3: true}); 50 | expect(query.toString()).to.equal('{ product(attr1: "value1", attr2: 2, attr3: true){} }'); 51 | }); 52 | 53 | it('should allow filter multiple times', () => { 54 | const query = new GraphQlQuery('product'); 55 | query.filter({attr1: 'value1'}) 56 | .filter({attr2: 2, attr3: true}) 57 | .filter({attr1: 'value2'}); 58 | expect(query.toString()).to.equal('{ product(attr1: "value2", attr2: 2, attr3: true){} }'); 59 | }); 60 | 61 | it('should support nested filtering with regular filtering', () => { 62 | const query = new GraphQlQuery('product').filter({attr1: {attr2: 'val1'}, attr3: 'val2'}); 63 | expect(query.toString()).to.equal('{ product(attr1: {attr2: "val1"}, attr3: "val2"){} }'); 64 | }); 65 | }); 66 | 67 | describe('select', () => { 68 | it('should support fields selection', () => { 69 | const query = new GraphQlQuery('product') 70 | .select('id', 'name'); 71 | expect(query.toString()).to.equal('{ product{id name} }'); 72 | }); 73 | 74 | it('should support fields selection with alias', () => { 75 | const query = new GraphQlQuery('product') 76 | .select({productId: 'id'}, 'name', {price: 'productPrice'}); 77 | expect(query.toString()).to.equal('{ product{productId: id name price: productPrice} }'); 78 | }); 79 | 80 | it('should support fields selection with arguments', () => { 81 | const query = new GraphQlQuery('product') 82 | .select({productId: 'id'}, 'name', {price: 'productPrice', _filter: {discounted: true}}); 83 | expect(query.toString()).to.equal('{ product{productId: id name price: productPrice(discounted: true)} }'); 84 | }); 85 | 86 | it('should support selection of a Query', () => { 87 | const mainMedia = new GraphQlQuery('media').select('url'); 88 | const product = new GraphQlQuery('product', {productId: 'f150b16a-79ef-ef81-50f9-22e2df631822'}) 89 | .select('id', 'name', mainMedia); 90 | expect(product.toString()).to 91 | .equal('{ product(productId: "f150b16a-79ef-ef81-50f9-22e2df631822"){id name media{url}} }'); 92 | }); 93 | 94 | it('should support selection of a Query with alias', () => { 95 | const mainMedia = new GraphQlQuery('media').select('url'); 96 | const product = new GraphQlQuery('product', {productId: 'f150b16a-79ef-ef81-50f9-22e2df631822'}) 97 | .select('id', 'name', {image: mainMedia}); 98 | expect(product.toString()).to 99 | .equal('{ product(productId: "f150b16a-79ef-ef81-50f9-22e2df631822"){id name image: media{url}} }'); 100 | }); 101 | }); 102 | 103 | describe('without body', () => { 104 | it('should support query without filters', () => { 105 | const query = new GraphQlQuery('product') 106 | .withoutBody(); 107 | expect(query.toString()).to.equal('{ product }'); 108 | }); 109 | 110 | it('should support query with filters', () => { 111 | const query = new GraphQlQuery('product') 112 | .withoutBody() 113 | .filter({attr1: 'value1', attr2: 2, attr3: true}); 114 | expect(query.toString()).to.equal('{ product(attr1: "value1", attr2: 2, attr3: true) }'); 115 | }); 116 | 117 | it('should not have body even with select', () => { 118 | const query = new GraphQlQuery('product') 119 | .withoutBody() 120 | .select('id', 'name'); 121 | expect(query.toString()).to.equal('{ product }'); 122 | }); 123 | }); 124 | 125 | describe('join', () => { 126 | it('should support joining 2 queries', () => { 127 | const mainMedia = new GraphQlQuery('media').select('url'); 128 | 129 | const query1 = new GraphQlQuery('product') 130 | .select({productId: 'id'}, 'name', {price: 'productPrice', _filter: {discounted: true}}); 131 | const query2 = new GraphQlQuery('order') 132 | .select('id', {totalValue: 'total'}); 133 | 134 | const finalQuery = query1.join(query2); 135 | expect(finalQuery.toString()).to 136 | .equal('{ product{productId: id name price: productPrice(discounted: true)} order{id totalValue: total} }'); 137 | }); 138 | 139 | it('should throw exception when selecting on join query', () => { 140 | const query1 = new GraphQlQuery('product') 141 | .select({productId: 'id'}, 'name', {price: 'productPrice', _filter: {discounted: true}}); 142 | const query2 = new GraphQlQuery('order') 143 | .select('id', {totalValue: 'total'}); 144 | const finalQuery = query1.join(query2); 145 | expect(finalQuery.select.bind(finalQuery, '1')).to.throw(Error); 146 | }); 147 | 148 | it('should throw exception when calling without body on join query', () => { 149 | const query1 = new GraphQlQuery('product') 150 | .select({productId: 'id'}, 'name', {price: 'productPrice', _filter: {discounted: true}}); 151 | const query2 = new GraphQlQuery('order') 152 | .select('id', {totalValue: 'total'}); 153 | const finalQuery = query1.join(query2); 154 | expect(finalQuery.withoutBody.bind(finalQuery)).to.throw(Error); 155 | }); 156 | 157 | it('should support joining queries without body with select and with filters', () => { 158 | const query1 = new GraphQlQuery('product') 159 | .withoutBody(); 160 | const query2 = new GraphQlQuery('order') 161 | .select('id', {totalValue: 'total'}); 162 | const query3 = new GraphQlQuery('order') 163 | .filter({attr1: 'value1', attr2: 2, attr3: true}); 164 | const finalQuery = query1.join(query2, query3); 165 | expect(finalQuery.toString()).to.equal('{ product order{id totalValue: total} order(attr1: "value1", attr2: 2, attr3: true){} }'); 166 | }); 167 | }); 168 | }); 169 | 170 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "es5", 5 | "moduleResolution": "node", 6 | "sourceMap": true, 7 | "outDir": "dist", 8 | "declaration": true, 9 | "types": ["node"] 10 | }, 11 | "include": [ 12 | "typings/**/*.d.ts" 13 | ], 14 | "files": [ 15 | "./src/GraphQlQuery.ts", 16 | "./test/GraphQlQuery.spec.ts" 17 | ] 18 | } -------------------------------------------------------------------------------- /typings.json: -------------------------------------------------------------------------------- 1 | { 2 | "globalDependencies": { 3 | "mocha": "registry:dt/mocha#2.2.5+20160720003353", 4 | "node": "registry:dt/node#6.0.0+20160728152422" 5 | }, 6 | "dependencies": { 7 | "chai": "registry:npm/chai#3.5.0+20160723033700" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /typings/globals/mocha/index.d.ts: -------------------------------------------------------------------------------- 1 | // Generated by typings 2 | // Source: https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/a361a8ab3c327f208d3f82ad206971d4a63d8c25/mocha/mocha.d.ts 3 | interface MochaSetupOptions { 4 | //milliseconds to wait before considering a test slow 5 | slow?: number; 6 | 7 | // timeout in milliseconds 8 | timeout?: number; 9 | 10 | // ui name "bdd", "tdd", "exports" etc 11 | ui?: string; 12 | 13 | //array of accepted globals 14 | globals?: any[]; 15 | 16 | // reporter instance (function or string), defaults to `mocha.reporters.Spec` 17 | reporter?: any; 18 | 19 | // bail on the first test failure 20 | bail?: boolean; 21 | 22 | // ignore global leaks 23 | ignoreLeaks?: boolean; 24 | 25 | // grep string or regexp to filter tests with 26 | grep?: any; 27 | } 28 | 29 | declare var mocha: Mocha; 30 | declare var describe: Mocha.IContextDefinition; 31 | declare var xdescribe: Mocha.IContextDefinition; 32 | // alias for `describe` 33 | declare var context: Mocha.IContextDefinition; 34 | // alias for `describe` 35 | declare var suite: Mocha.IContextDefinition; 36 | declare var it: Mocha.ITestDefinition; 37 | declare var xit: Mocha.ITestDefinition; 38 | // alias for `it` 39 | declare var test: Mocha.ITestDefinition; 40 | declare var specify: Mocha.ITestDefinition; 41 | 42 | interface MochaDone { 43 | (error?: any): any; 44 | } 45 | 46 | interface ActionFunction { 47 | (done: MochaDone): any | PromiseLike 48 | } 49 | 50 | declare function setup(action: ActionFunction): void; 51 | declare function teardown(action: ActionFunction): void; 52 | declare function suiteSetup(action: ActionFunction): void; 53 | declare function suiteTeardown(action: ActionFunction): void; 54 | declare function before(action: ActionFunction): void; 55 | declare function before(description: string, action: ActionFunction): void; 56 | declare function after(action: ActionFunction): void; 57 | declare function after(description: string, action: ActionFunction): void; 58 | declare function beforeEach(action: ActionFunction): void; 59 | declare function beforeEach(description: string, action: ActionFunction): void; 60 | declare function afterEach(action: ActionFunction): void; 61 | declare function afterEach(description: string, action: ActionFunction): void; 62 | 63 | declare class Mocha { 64 | currentTest: Mocha.ITestDefinition; 65 | constructor(options?: { 66 | grep?: RegExp; 67 | ui?: string; 68 | reporter?: string; 69 | timeout?: number; 70 | bail?: boolean; 71 | }); 72 | 73 | /** Setup mocha with the given options. */ 74 | setup(options: MochaSetupOptions): Mocha; 75 | bail(value?: boolean): Mocha; 76 | addFile(file: string): Mocha; 77 | /** Sets reporter by name, defaults to "spec". */ 78 | reporter(name: string): Mocha; 79 | /** Sets reporter constructor, defaults to mocha.reporters.Spec. */ 80 | reporter(reporter: (runner: Mocha.IRunner, options: any) => any): Mocha; 81 | ui(value: string): Mocha; 82 | grep(value: string): Mocha; 83 | grep(value: RegExp): Mocha; 84 | invert(): Mocha; 85 | ignoreLeaks(value: boolean): Mocha; 86 | checkLeaks(): Mocha; 87 | /** 88 | * Function to allow assertion libraries to throw errors directly into mocha. 89 | * This is useful when running tests in a browser because window.onerror will 90 | * only receive the 'message' attribute of the Error. 91 | */ 92 | throwError(error: Error): void; 93 | /** Enables growl support. */ 94 | growl(): Mocha; 95 | globals(value: string): Mocha; 96 | globals(values: string[]): Mocha; 97 | useColors(value: boolean): Mocha; 98 | useInlineDiffs(value: boolean): Mocha; 99 | timeout(value: number): Mocha; 100 | slow(value: number): Mocha; 101 | enableTimeouts(value: boolean): Mocha; 102 | asyncOnly(value: boolean): Mocha; 103 | noHighlighting(value: boolean): Mocha; 104 | /** Runs tests and invokes `onComplete()` when finished. */ 105 | run(onComplete?: (failures: number) => void): Mocha.IRunner; 106 | } 107 | 108 | // merge the Mocha class declaration with a module 109 | declare namespace Mocha { 110 | /** Partial interface for Mocha's `Runnable` class. */ 111 | interface IRunnable { 112 | title: string; 113 | fn: Function; 114 | async: boolean; 115 | sync: boolean; 116 | timedOut: boolean; 117 | } 118 | 119 | /** Partial interface for Mocha's `Suite` class. */ 120 | interface ISuite { 121 | parent: ISuite; 122 | title: string; 123 | 124 | fullTitle(): string; 125 | } 126 | 127 | /** Partial interface for Mocha's `Test` class. */ 128 | interface ITest extends IRunnable { 129 | parent: ISuite; 130 | pending: boolean; 131 | 132 | fullTitle(): string; 133 | } 134 | 135 | /** Partial interface for Mocha's `Runner` class. */ 136 | interface IRunner {} 137 | 138 | interface IContextDefinition { 139 | (description: string, spec: () => void): ISuite; 140 | only(description: string, spec: () => void): ISuite; 141 | skip(description: string, spec: () => void): void; 142 | timeout(ms: number): void; 143 | } 144 | 145 | interface ITestDefinition { 146 | (expectation: string, assertion?: ActionFunction): ITest; 147 | only(expectation: string, assertion?: ActionFunction): ITest; 148 | skip(expectation: string, assertion?: ActionFunction): void; 149 | timeout(ms: number): void; 150 | state: "failed" | "passed"; 151 | } 152 | 153 | export module reporters { 154 | export class Base { 155 | stats: { 156 | suites: number; 157 | tests: number; 158 | passes: number; 159 | pending: number; 160 | failures: number; 161 | }; 162 | 163 | constructor(runner: IRunner); 164 | } 165 | 166 | export class Doc extends Base {} 167 | export class Dot extends Base {} 168 | export class HTML extends Base {} 169 | export class HTMLCov extends Base {} 170 | export class JSON extends Base {} 171 | export class JSONCov extends Base {} 172 | export class JSONStream extends Base {} 173 | export class Landing extends Base {} 174 | export class List extends Base {} 175 | export class Markdown extends Base {} 176 | export class Min extends Base {} 177 | export class Nyan extends Base {} 178 | export class Progress extends Base { 179 | /** 180 | * @param options.open String used to indicate the start of the progress bar. 181 | * @param options.complete String used to indicate a complete test on the progress bar. 182 | * @param options.incomplete String used to indicate an incomplete test on the progress bar. 183 | * @param options.close String used to indicate the end of the progress bar. 184 | */ 185 | constructor(runner: IRunner, options?: { 186 | open?: string; 187 | complete?: string; 188 | incomplete?: string; 189 | close?: string; 190 | }); 191 | } 192 | export class Spec extends Base {} 193 | export class TAP extends Base {} 194 | export class XUnit extends Base { 195 | constructor(runner: IRunner, options?: any); 196 | } 197 | } 198 | } 199 | 200 | declare module "mocha" { 201 | export = Mocha; 202 | } 203 | -------------------------------------------------------------------------------- /typings/globals/mocha/typings.json: -------------------------------------------------------------------------------- 1 | { 2 | "resolution": "main", 3 | "tree": { 4 | "src": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/a361a8ab3c327f208d3f82ad206971d4a63d8c25/mocha/mocha.d.ts", 5 | "raw": "registry:dt/mocha#2.2.5+20160720003353", 6 | "typings": "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/a361a8ab3c327f208d3f82ad206971d4a63d8c25/mocha/mocha.d.ts" 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /typings/index.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /wallaby.js: -------------------------------------------------------------------------------- 1 | module.exports = function (wallaby) { 2 | return { 3 | files: [ 4 | 'src/**/*.ts' 5 | ], 6 | 7 | tests: [ 8 | 'test/**/*.spec.ts' 9 | ], 10 | env: { 11 | type: 'node' 12 | }, 13 | testFramework: 'mocha' 14 | }; 15 | }; 16 | -------------------------------------------------------------------------------- /wix-graphql-query-builder.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | --------------------------------------------------------------------------------