<commit_before>var util = require('util');
var crypto = require('crypto');
var child_process = require('child_process');
var os = require('os');
var fs = require('fs');
var url = require('url');
require('follow-redirects').maxRedirects = 12;
var http = require('follow-redirects').http;
http.globalAgent.maxSockets = Infinity;
var https = require('follow-redirects').https;
https.globalAgent.maxSockets = Infinity;
var mkdirp = require('mkdirp');
var path = require('path');

var DOWNLOAD_RETRY_INTERVAL = 2;

// add startsWith/endsWith functions to string
if (typeof String.prototype.startsWith != 'function') {
	String.prototype.startsWith = function(str) {
		return this.slice(0, str.length) == str;
	};
}

if (typeof String.prototype.endsWith != 'function') {
	String.prototype.endsWith = function(str) {
		return this.slice(-str.length) == str;
	};
}

if (typeof String.prototype.md5 != 'function') {
	String.prototype.md5 = function() {
		return crypto.createHash('md5').update(new Buffer(this.toString())).digest('hex');
	};
}

if (typeof String.prototype.exec != 'function') {
	String.prototype.exec = function(callback, errorCallback) {
		var cmd = this;
		var childProcess = child_process.exec(cmd, function (error, stdout, stderr) {
			KalturaLogger.log('Command: ' + cmd);
			KalturaLogger.debug('Standard output: ' + stdout);

			if(stderr.length){
				KalturaLogger.log('Standard error: ' + stderr);
			}

		    if (error) {
		    	if(errorCallback){
		    		errorCallback(error);
		    	}
		    	else{
		    		var exception = new Error();
		    		KalturaLogger.error('Exec: ' + error + '\n' + exception.stack);
		    	}
		    }
		    else if(callback){
		    	callback(stdout);
		    }
		});

		KalturaLogger.debug('Started cli process [' + childProcess.pid + ']: ' + cmd);
	};
}

if (typeof Array.prototype.unique != 'function') {
	Array.prototype.unique = function() {
	    return this.reduce(function(p, c) {
	        if (p.indexOf(c) < 0)
	        	p.push(c);
	        return p;
	    }, []);
	};
}

if (typeof Array.prototype.diff != 'function') {
	Array.prototype.diff = function(arr) {
		var retArr = [];

		thisLoop: for (var k = 0; k < this.length; k++) {
		    for (var i = 0; i < arr.length; i++) {
		    	if(this[k] == arr[i]){
		    		continue thisLoop;
		    	}
		    }
		    retArr.push(this[k]);
		}
		return retArr;
	};
}

if (typeof Buffer.prototype.md5 != 'function') {
	Buffer.prototype.md5 = function() {
		return crypto.createHash('md5').update(this).digest('hex');
	};
}

KalturaUtils = {
	getUniqueId : function(){
		return Math.floor(Math.random() * 10000000000000001).toString(36);
	},

	seconds2npt: function( sec, show_ms ) {
		if ( isNaN( sec ) ) {
			return '0:00:00';
		}

		var tm = KalturaUtils.seconds2Measurements( sec );

		// Round the number of seconds to the required number of significant
		// digits
		if ( show_ms ) {
			tm.seconds = Math.round( tm.seconds * 1000 ) / 1000;
		} else {
			tm.seconds = Math.round( tm.seconds );
		}
		if ( tm.seconds < 10 ){
			tm.seconds = '0' +	tm.seconds;
		}
		var hoursStr;
		if( tm.hours == 0 ){
			hoursStr = '';
		} else {
			if ( tm.minutes < 10 )
				tm.minutes = '0' + tm.minutes;

			hoursStr = tm.hours + ":";
		}
		return hoursStr + tm.minutes + ":" + tm.seconds;
	},

	seconds2Measurements: function ( sec ){
		var tm = {};
		tm.days = Math.floor( sec / ( 3600 * 24 ) );
		tm.hours = Math.floor( Math.round( sec ) / 3600 );
		tm.minutes = Math.floor( ( Math.round( sec ) / 60 ) % 60 );
		tm.seconds = Math.round(sec) % 60;
		return tm;
	},

	getHttpModuleByProtocol : function(protocol, urlStr){
		if(!protocol){
			var parsedUrl = url.parse(urlStr);
			protocol = parsedUrl.protocol;
		}
		if(protocol == 'https:'){
			return https;
		}
		return http;
	},

	downloadMultiHttpUrls : function(urls, filePaths, successCallback, errorCallback) {
		var missingResults = urls.length;

		if(!filePaths){
			filePaths = [];
			for(var i = 0; i < urls.length; i++){
				filePaths[i] = KalturaConfig.config.cloud.sharedBasePath + '/tmp/' + KalturaUtils.getUniqueId();
			}
		}

		var singleSuccessCallback = function(){
			missingResults--;

			if(!missingResults){
				successCallback(filePaths);
			}
		};

		for(var i = 0; i < urls.length; i++){
			KalturaUtils.downloadHttpUrl(urls[i], {filePath: filePaths[i]}, singleSuccessCallback, errorCallback);
		}
	},

	getHttpUrl : function(urlStr, headers, successCallback, errorCallback) {
		var parsedUrl = url.parse(urlStr);
		var httpModule = KalturaUtils.getHttpModuleByProtocol(parsedUrl.protocol);
		var options = {
			hostname : parsedUrl.hostname,
			port : parsedUrl.port,
			path : parsedUrl.path,
			method : 'GET',
		};
		if (headers){
			options.headers = headers;
		}

		var request = httpModule.request(options, function(response) {
			var fullData = '';
			response.on('data', function(data) {
				fullData += data;
			});
			response.on('end', function() {
				if(response.statusCode != 200){
					if(errorCallback){
						return errorCallback('Invalid http status: ' + response.statusCode);
					}
					else{
						KalturaLogger.error('Invalid http status: ' + response.statusCode + ' while trying to fetch ' + urlStr);
						return;
					}
				}
				if(successCallback){
					successCallback(fullData);
				}
			});
		});

		request.on('error', function(e) {
			if(errorCallback){
				errorCallback(e.message);
			}
		});

		request.end();
	},

	getHttpUrlByteLimit : function(urlStr, headers, bytes, successCallback, errorCallback) {
		var parsedUrl = url.parse(urlStr);
		var httpModule = KalturaUtils.getHttpModuleByProtocol(parsedUrl.protocol);
		var options = {
			hostname : parsedUrl.hostname,
			port : parsedUrl.port,
			path : parsedUrl.path,
			method : 'GET',
		};
		if (headers){
			options.headers = headers;
		}

		var request = httpModule.request(options, function(response) {
			var dataBuffers = [];
			var length = 0;
			response.on('data', function(data) {
				  length += data.length;
				  dataBuffers.push(data);
				  KalturaLogger.debug('current length=' + length);
			      if (length >= bytes){
			        response.destroy();
			      }
			});
			response.on('end', function() {
				if(response.statusCode != 200){
					if(errorCallback){
						return errorCallback('Invalid http status: ' + response.statusCode);
					}
					else{
						KalturaLogger.error('Invalid http status: ' + response.statusCode + ' while trying to fetch ' + urlStr);
						return;
					}
				}
				if(successCallback){
					KalturaLogger.log('Downloaded [' + length + '] bytes');
					 var bytesBuffer = Buffer.concat(dataBuffers, bytes);
					successCallback(bytesBuffer);
				}
			});
		});

		request.on('error', function(e) {
			if(errorCallback){
				errorCallback(e.message);
			}
		});

		request.end();
	},

	buildFilePath: function(baseDir, fileName){

		if(!fileName)
			return;
		var dir1 = fileName.substring(0,2);
		var dir2 = fileName.substring(2,4);
		return path.join(KalturaConfig.config.cloud.sharedBasePath, baseDir, dir1, dir2, fileName);
	},

	createFilePath : function(filePath, successCallback, errorCallback) {
		var dirName= path.dirname(filePath);
		mkdirp(dirName, function (err) {
		    if (err){
		    	if(errorCallback){
		    		errorCallback(err);
		    	}
		    	else{
		    		KalturaLogger.error('Failed to create dir path: ' + err);
		    	}
		    }
		    else{
		    	successCallback();
		    }
		});
	},

	downloadHttpUrl : function(urlStr, options, successCallback, errorCallback) {
		KalturaLogger.debug('Starting download [' + urlStr + ']');

		var watchFileOnFs = function(filePath, retries, successCallback, errorCallback){
			KalturaLogger.log('Watching file download to: [' + filePath + '] retries left' + '[' + retries + ']');
			setTimeout(function(){
				fs.exists(filePath, function(exists){
					if(exists){
						KalturaLogger.log('File from url [' + urlStr + '], already downloaded to [' + filePath + ']');
						successCallback(filePath);
					}
					else{
						retries --;
						if(retries == 0)
							return errorCallback('download timeout');

						watchFileOnFs(filePath, retries, successCallback, errorCallback);
					}
				});
			}, DOWNLOAD_RETRY_INTERVAL * 1000);
		};

		var tempPath = null;

		fs.exists(options.filePath, function(exists){
			if(exists){
				KalturaLogger.log('File from url [' + urlStr + '], already downloaded to [' + options.filePath + ']');
				successCallback(options.filePath);
			}
			else{
				var fileDownloadingKey = KalturaCache.getKey(KalturaCache.FILE_DOWNLOADING_KEY_PREFIX, [options.filePath]);
				KalturaCache.add(fileDownloadingKey, true, KalturaConfig.config.cache.fileDownloadTimeout, function(){
					tempPath = KalturaConfig.config.cloud.sharedBasePath + '/tmp/' + KalturaUtils.getUniqueId();
					KalturaLogger.log('File from url [' + urlStr + '], downloading to temp path[' + tempPath + ']');

					var parsedUrl = url.parse(urlStr);
					var httpModule = KalturaUtils.getHttpModuleByProtocol(parsedUrl.protocol);
					options.hostname = parsedUrl.hostname;
					options.port = parsedUrl.port;
					options.path = parsedUrl.path;
					options.method = 'GET';

					var localFile = fs.createWriteStream(tempPath);
					var request = httpModule.request(options, function(response) {
						response.pipe(localFile);

						localFile.on('finish', function() {
							localFile.close();
							KalturaUtils.createFilePath(options.filePath, function(){
								KalturaLogger.log('Moving temp file[' + tempPath + '] to [' + options.filePath + ']');
								fs.rename(tempPath, options.filePath, function(){
									successCallback(options.filePath);
								});
							}, errorCallback);
					    });

						response.on('data', function() { /* do nothing */ });

						response.on('end', function() { /* do nothing */ });
					});

					request.on('error', function(e) {
						errorCallback(e.message);
					});

					request.end();

				}, function (err) {
					// retry check if file is on file system
					KalturaLogger.log('File from url [' + urlStr + '] already downloading');
					var retries = KalturaConfig.config.cache.fileDownloadTimeout / DOWNLOAD_RETRY_INTERVAL;
					watchFileOnFs(options.filePath, retries, successCallback, errorCallback);
				});

			}

		});
	},

	readFromFileByLength : function(fd, callback, errorCallback){
		var buffer = new Buffer(4);
		fs.read(fd, buffer, 0, 4, null, function(err, bytesRead, buffer){
			if(err){
				errorCallback(err);
				return;
			}
			var length = buffer.readUInt32BE(0);
			var itemBuffer = new Buffer(length);
			fs.read(fd, itemBuffer, 0, length, null, function(err, bytesRead, itemBuffer){
				if(err){
					errorCallback(err);
					return;
				}
				callback(itemBuffer);
			});
		});
	},

	writeToFileByLength : function(fd, data){
		var lBuffer = new Buffer(4);
		lBuffer.writeUInt32BE(data.length, 0);
		fd.write(lBuffer);
		fd.write(data);
	}
};

<commit_msg>#PLAT-4203 concat full buffers lenght to avoid targetStart out of bounds exception<commit_after>var util = require('util');
var crypto = require('crypto');
var child_process = require('child_process');
var os = require('os');
var fs = require('fs');
var url = require('url');
require('follow-redirects').maxRedirects = 12;
var http = require('follow-redirects').http;
http.globalAgent.maxSockets = Infinity;
var https = require('follow-redirects').https;
https.globalAgent.maxSockets = Infinity;
var mkdirp = require('mkdirp');
var path = require('path');

var DOWNLOAD_RETRY_INTERVAL = 2;

// add startsWith/endsWith functions to string
if (typeof String.prototype.startsWith != 'function') {
	String.prototype.startsWith = function(str) {
		return this.slice(0, str.length) == str;
	};
}

if (typeof String.prototype.endsWith != 'function') {
	String.prototype.endsWith = function(str) {
		return this.slice(-str.length) == str;
	};
}

if (typeof String.prototype.md5 != 'function') {
	String.prototype.md5 = function() {
		return crypto.createHash('md5').update(new Buffer(this.toString())).digest('hex');
	};
}

if (typeof String.prototype.exec != 'function') {
	String.prototype.exec = function(callback, errorCallback) {
		var cmd = this;
		var childProcess = child_process.exec(cmd, function (error, stdout, stderr) {
			KalturaLogger.log('Command: ' + cmd);
			KalturaLogger.debug('Standard output: ' + stdout);

			if(stderr.length){
				KalturaLogger.log('Standard error: ' + stderr);
			}

		    if (error) {
		    	if(errorCallback){
		    		errorCallback(error);
		    	}
		    	else{
		    		var exception = new Error();
		    		KalturaLogger.error('Exec: ' + error + '\n' + exception.stack);
		    	}
		    }
		    else if(callback){
		    	callback(stdout);
		    }
		});

		KalturaLogger.debug('Started cli process [' + childProcess.pid + ']: ' + cmd);
	};
}

if (typeof Array.prototype.unique != 'function') {
	Array.prototype.unique = function() {
	    return this.reduce(function(p, c) {
	        if (p.indexOf(c) < 0)
	        	p.push(c);
	        return p;
	    }, []);
	};
}

if (typeof Array.prototype.diff != 'function') {
	Array.prototype.diff = function(arr) {
		var retArr = [];

		thisLoop: for (var k = 0; k < this.length; k++) {
		    for (var i = 0; i < arr.length; i++) {
		    	if(this[k] == arr[i]){
		    		continue thisLoop;
		    	}
		    }
		    retArr.push(this[k]);
		}
		return retArr;
	};
}

if (typeof Buffer.prototype.md5 != 'function') {
	Buffer.prototype.md5 = function() {
		return crypto.createHash('md5').update(this).digest('hex');
	};
}

KalturaUtils = {
	getUniqueId : function(){
		return Math.floor(Math.random() * 10000000000000001).toString(36);
	},

	seconds2npt: function( sec, show_ms ) {
		if ( isNaN( sec ) ) {
			return '0:00:00';
		}

		var tm = KalturaUtils.seconds2Measurements( sec );

		// Round the number of seconds to the required number of significant
		// digits
		if ( show_ms ) {
			tm.seconds = Math.round( tm.seconds * 1000 ) / 1000;
		} else {
			tm.seconds = Math.round( tm.seconds );
		}
		if ( tm.seconds < 10 ){
			tm.seconds = '0' +	tm.seconds;
		}
		var hoursStr;
		if( tm.hours == 0 ){
			hoursStr = '';
		} else {
			if ( tm.minutes < 10 )
				tm.minutes = '0' + tm.minutes;

			hoursStr = tm.hours + ":";
		}
		return hoursStr + tm.minutes + ":" + tm.seconds;
	},

	seconds2Measurements: function ( sec ){
		var tm = {};
		tm.days = Math.floor( sec / ( 3600 * 24 ) );
		tm.hours = Math.floor( Math.round( sec ) / 3600 );
		tm.minutes = Math.floor( ( Math.round( sec ) / 60 ) % 60 );
		tm.seconds = Math.round(sec) % 60;
		return tm;
	},

	getHttpModuleByProtocol : function(protocol, urlStr){
		if(!protocol){
			var parsedUrl = url.parse(urlStr);
			protocol = parsedUrl.protocol;
		}
		if(protocol == 'https:'){
			return https;
		}
		return http;
	},

	downloadMultiHttpUrls : function(urls, filePaths, successCallback, errorCallback) {
		var missingResults = urls.length;

		if(!filePaths){
			filePaths = [];
			for(var i = 0; i < urls.length; i++){
				filePaths[i] = KalturaConfig.config.cloud.sharedBasePath + '/tmp/' + KalturaUtils.getUniqueId();
			}
		}

		var singleSuccessCallback = function(){
			missingResults--;

			if(!missingResults){
				successCallback(filePaths);
			}
		};

		for(var i = 0; i < urls.length; i++){
			KalturaUtils.downloadHttpUrl(urls[i], {filePath: filePaths[i]}, singleSuccessCallback, errorCallback);
		}
	},

	getHttpUrl : function(urlStr, headers, successCallback, errorCallback) {
		var parsedUrl = url.parse(urlStr);
		var httpModule = KalturaUtils.getHttpModuleByProtocol(parsedUrl.protocol);
		var options = {
			hostname : parsedUrl.hostname,
			port : parsedUrl.port,
			path : parsedUrl.path,
			method : 'GET',
		};
		if (headers){
			options.headers = headers;
		}

		var request = httpModule.request(options, function(response) {
			var fullData = '';
			response.on('data', function(data) {
				fullData += data;
			});
			response.on('end', function() {
				if(response.statusCode != 200){
					if(errorCallback){
						return errorCallback('Invalid http status: ' + response.statusCode);
					}
					else{
						KalturaLogger.error('Invalid http status: ' + response.statusCode + ' while trying to fetch ' + urlStr);
						return;
					}
				}
				if(successCallback){
					successCallback(fullData);
				}
			});
		});

		request.on('error', function(e) {
			if(errorCallback){
				errorCallback(e.message);
			}
		});

		request.end();
	},

	getHttpUrlByteLimit : function(urlStr, headers, bytes, successCallback, errorCallback) {
		var parsedUrl = url.parse(urlStr);
		var httpModule = KalturaUtils.getHttpModuleByProtocol(parsedUrl.protocol);
		var options = {
			hostname : parsedUrl.hostname,
			port : parsedUrl.port,
			path : parsedUrl.path,
			method : 'GET',
		};
		if (headers){
			options.headers = headers;
		}

		var request = httpModule.request(options, function(response) {
			var dataBuffers = [];
			var length = 0;
			response.on('data', function(data) {
				  length += data.length;
				  dataBuffers.push(data);
				  KalturaLogger.debug('current length=' + length);
			      if (length >= bytes){
			        response.destroy();
			      }
			});
			response.on('end', function() {
				if(response.statusCode != 200){
					if(errorCallback){
						return errorCallback('Invalid http status: ' + response.statusCode);
					}
					else{
						KalturaLogger.error('Invalid http status: ' + response.statusCode + ' while trying to fetch ' + urlStr);
						return;
					}
				}
				if(successCallback){
					KalturaLogger.log('Downloaded [' + length + '] bytes');
					 var bytesBuffer = Buffer.concat(dataBuffers, length);
					successCallback(bytesBuffer.slice(0, bytes));
				}
			});
		});

		request.on('error', function(e) {
			if(errorCallback){
				errorCallback(e.message);
			}
		});

		request.end();
	},

	buildFilePath: function(baseDir, fileName){

		if(!fileName)
			return;
		var dir1 = fileName.substring(0,2);
		var dir2 = fileName.substring(2,4);
		return path.join(KalturaConfig.config.cloud.sharedBasePath, baseDir, dir1, dir2, fileName);
	},

	createFilePath : function(filePath, successCallback, errorCallback) {
		var dirName= path.dirname(filePath);
		mkdirp(dirName, function (err) {
		    if (err){
		    	if(errorCallback){
		    		errorCallback(err);
		    	}
		    	else{
		    		KalturaLogger.error('Failed to create dir path: ' + err);
		    	}
		    }
		    else{
		    	successCallback();
		    }
		});
	},

	downloadHttpUrl : function(urlStr, options, successCallback, errorCallback) {
		KalturaLogger.debug('Starting download [' + urlStr + ']');

		var watchFileOnFs = function(filePath, retries, successCallback, errorCallback){
			KalturaLogger.log('Watching file download to: [' + filePath + '] retries left' + '[' + retries + ']');
			setTimeout(function(){
				fs.exists(filePath, function(exists){
					if(exists){
						KalturaLogger.log('File from url [' + urlStr + '], already downloaded to [' + filePath + ']');
						successCallback(filePath);
					}
					else{
						retries --;
						if(retries == 0)
							return errorCallback('download timeout');

						watchFileOnFs(filePath, retries, successCallback, errorCallback);
					}
				});
			}, DOWNLOAD_RETRY_INTERVAL * 1000);
		};

		var tempPath = null;

		fs.exists(options.filePath, function(exists){
			if(exists){
				KalturaLogger.log('File from url [' + urlStr + '], already downloaded to [' + options.filePath + ']');
				successCallback(options.filePath);
			}
			else{
				var fileDownloadingKey = KalturaCache.getKey(KalturaCache.FILE_DOWNLOADING_KEY_PREFIX, [options.filePath]);
				KalturaCache.add(fileDownloadingKey, true, KalturaConfig.config.cache.fileDownloadTimeout, function(){
					tempPath = KalturaConfig.config.cloud.sharedBasePath + '/tmp/' + KalturaUtils.getUniqueId();
					KalturaLogger.log('File from url [' + urlStr + '], downloading to temp path[' + tempPath + ']');

					var parsedUrl = url.parse(urlStr);
					var httpModule = KalturaUtils.getHttpModuleByProtocol(parsedUrl.protocol);
					options.hostname = parsedUrl.hostname;
					options.port = parsedUrl.port;
					options.path = parsedUrl.path;
					options.method = 'GET';

					var localFile = fs.createWriteStream(tempPath);
					var request = httpModule.request(options, function(response) {
						response.pipe(localFile);

						localFile.on('finish', function() {
							localFile.close();
							KalturaUtils.createFilePath(options.filePath, function(){
								KalturaLogger.log('Moving temp file[' + tempPath + '] to [' + options.filePath + ']');
								fs.rename(tempPath, options.filePath, function(){
									successCallback(options.filePath);
								});
							}, errorCallback);
					    });

						response.on('data', function() { /* do nothing */ });

						response.on('end', function() { /* do nothing */ });
					});

					request.on('error', function(e) {
						errorCallback(e.message);
					});

					request.end();

				}, function (err) {
					// retry check if file is on file system
					KalturaLogger.log('File from url [' + urlStr + '] already downloading');
					var retries = KalturaConfig.config.cache.fileDownloadTimeout / DOWNLOAD_RETRY_INTERVAL;
					watchFileOnFs(options.filePath, retries, successCallback, errorCallback);
				});

			}

		});
	},

	readFromFileByLength : function(fd, callback, errorCallback){
		var buffer = new Buffer(4);
		fs.read(fd, buffer, 0, 4, null, function(err, bytesRead, buffer){
			if(err){
				errorCallback(err);
				return;
			}
			var length = buffer.readUInt32BE(0);
			var itemBuffer = new Buffer(length);
			fs.read(fd, itemBuffer, 0, length, null, function(err, bytesRead, itemBuffer){
				if(err){
					errorCallback(err);
					return;
				}
				callback(itemBuffer);
			});
		});
	},

	writeToFileByLength : function(fd, data){
		var lBuffer = new Buffer(4);
		lBuffer.writeUInt32BE(data.length, 0);
		fd.write(lBuffer);
		fd.write(data);
	}
};

<|endoftext|>


<commit_before>'use strict';

const CommonImport = require('../../util/CommonImport');

const types = ['query', 'shape'];

const Path = require('./Path');
const Query = require('./Query');

class Gremlin {

  constructor(promisify, requestWithDefaultOpts) {
    this._promisify = promisify;
    this._request = requestWithDefaultOpts;
  }

  type(type) {
    if (!type || types.indexOf(type) === -1) {
      throw new Error("Please pass in valid type, can be: 'query' or 'shape'.");
    }
    const gremlin = new this.constructor(this._promisify, this._request);
    gremlin._query = gremlin._query.bind(gremlin, type);
    return gremlin;
  }

  V() {
    return this._v(Array.prototype.slice.call(arguments));
  }

  Vertex() {
    return this._v(Array.prototype.slice.call(arguments));
  }

  M() {
    return this.Morphism();
  }

  Morphism() {
    const path = new Path(['M', []]);
    path._query = this._query;
    return path;
  }

  _v() {
    const query = new Query(['V', arguments[0]], this._promisify);
    query._query = this._query;
    return query;
  }

  _query(type, gremlinText, callback) {
    if (types.indexOf(type) === -1) {
      type = types[0];
    }
    this._request.post({
      uri: '/' + type + '/gremlin',
      body: gremlinText
    }, (err, res, resBody) => {
      if (err) {
        callback(err);
      } else {
        callback(null, JSON.parse(resBody));
      }
    });
  }

}

module.exports = Gremlin;

<commit_msg>Path object should not know _query function.<commit_after>'use strict';

const CommonImport = require('../../util/CommonImport');

const types = ['query', 'shape'];

const Path = require('./Path');
const Query = require('./Query');

class Gremlin {

  constructor(promisify, requestWithDefaultOpts) {
    this._promisify = promisify;
    this._request = requestWithDefaultOpts;
  }

  type(type) {
    if (!type || types.indexOf(type) === -1) {
      throw new Error("Please pass in valid type, can be: 'query' or 'shape'.");
    }
    const gremlin = new this.constructor(this._promisify, this._request);
    gremlin._query = gremlin._query.bind(gremlin, type);
    return gremlin;
  }

  V() {
    return this._v(Array.prototype.slice.call(arguments));
  }

  Vertex() {
    return this._v(Array.prototype.slice.call(arguments));
  }

  M() {
    return this.Morphism();
  }

  Morphism() {
    const path = new Path(['M', []]);
    // path._query = this._query;
    return path;
  }

  _v() {
    const query = new Query(['V', arguments[0]], this._promisify);
    query._query = this._query;
    return query;
  }

  _query(type, gremlinText, callback) {
    if (types.indexOf(type) === -1) {
      type = types[0];
    }
    this._request.post({
      uri: '/' + type + '/gremlin',
      body: gremlinText
    }, (err, res, resBody) => {
      if (err) {
        callback(err);
      } else {
        callback(null, JSON.parse(resBody));
      }
    });
  }

}

module.exports = Gremlin;

<|endoftext|>


<commit_before>var parser = require('./parser');
var factory = require('./factory');
var notifier = require('./notifier');
var ServiceProxy = require('../lib/proxy');

var services = {};
var proxies = {};

function addProxy(name, instance) {
  if (!proxies.hasOwnProperty(name)) {
    proxies[name] = [];
  }
  proxies[name].push(instance);
}

function load(name) {
  if (services.hasOwnProperty(name)) {
    var serviceInstance = factory.create(load)(services[name]);
    services[name].instances.push(serviceInstance);
    return serviceInstance;
  } else {
    var proxyName = /^\$(.*)\$$/g;
    var result = proxyName.exec(name);
    if (result === null) {
      throw new Error('No service with name \'' + name + '\' was registered!');
      // return null;
    } else {
      var proxy = new ServiceProxy();
      var serviceName = result[1];
      proxy.service = load(serviceName);
      addProxy(serviceName, proxy);
      return proxy;
    }
  }
}

module.exports.load = load;

function createAddCallbackFn(serviceData) {
  return {
    callback: function(callback) {
      serviceData.callback = callback;
    }
  }
}

module.exports.save = function(name, service, singleton) {
  if (name === null) {
    name = extractServiceName(service);
  }
  var serviceData = {
    name: name,
    constructor: service,
    singleton: singleton,
    dependencies: parser.parameterNames(service.toString()),
    instances: [],
    callback: null
  };
  var alreadyExist = services.hasOwnProperty(name);
  services[name] = serviceData;
  if (alreadyExist) {
    factory.remove(name);
    notifier.notifyInstance(services, name, load);
    notifier.notifyProxies(proxies[name], loadServiceFn(name));
  }
  return createAddCallbackFn(serviceData);
};

module.exports.clean = function() {
  services = {};
  factory.clean();
};

function lowerCaseFirstLetter(string) {
  return string.charAt(0).toLowerCase() + string.slice(1);
}

function extractServiceName(service) {
  return lowerCaseFirstLetter(parser.functionName(service));
}

function loadServiceFn(serviceName) {
  return function() {
    return load(serviceName);
  }
}
<commit_msg>Remove comment<commit_after>var parser = require('./parser');
var factory = require('./factory');
var notifier = require('./notifier');
var ServiceProxy = require('../lib/proxy');

var services = {};
var proxies = {};

function addProxy(name, instance) {
  if (!proxies.hasOwnProperty(name)) {
    proxies[name] = [];
  }
  proxies[name].push(instance);
}

function load(name) {
  if (services.hasOwnProperty(name)) {
    var serviceInstance = factory.create(load)(services[name]);
    services[name].instances.push(serviceInstance);
    return serviceInstance;
  } else {
    var proxyName = /^\$(.*)\$$/g;
    var result = proxyName.exec(name);
    if (result === null) {
      throw new Error('No service with name \'' + name + '\' was registered!');
    } else {
      var proxy = new ServiceProxy();
      var serviceName = result[1];
      proxy.service = load(serviceName);
      addProxy(serviceName, proxy);
      return proxy;
    }
  }
}

module.exports.load = load;

function createAddCallbackFn(serviceData) {
  return {
    callback: function(callback) {
      serviceData.callback = callback;
    }
  }
}

module.exports.save = function(name, service, singleton) {
  if (name === null) {
    name = extractServiceName(service);
  }
  var serviceData = {
    name: name,
    constructor: service,
    singleton: singleton,
    dependencies: parser.parameterNames(service.toString()),
    instances: [],
    callback: null
  };
  var alreadyExist = services.hasOwnProperty(name);
  services[name] = serviceData;
  if (alreadyExist) {
    factory.remove(name);
    notifier.notifyInstance(services, name, load);
    notifier.notifyProxies(proxies[name], loadServiceFn(name));
  }
  return createAddCallbackFn(serviceData);
};

module.exports.clean = function() {
  services = {};
  factory.clean();
};

function lowerCaseFirstLetter(string) {
  return string.charAt(0).toLowerCase() + string.slice(1);
}

function extractServiceName(service) {
  return lowerCaseFirstLetter(parser.functionName(service));
}

function loadServiceFn(serviceName) {
  return function() {
    return load(serviceName);
  }
}
<|endoftext|>


<commit_before>"use strict"

const fmt = require("./fmt")
const $ = require("./utils/logging")
const { formatTime } = require("./fn")

module.exports = function () {
	return this
		.on("fly_run", file => {
			$.log(`Flying with ${fmt.path(file)}`)
		})

		.on("flyfile_not_found", () => {
			$.log("Flyfile not found!")
			process.exit(1)
		})

		.on("fly_watch", () => {
			$.log(fmt.warn("Watching files..."))
		})

		.on("fly_watch_event", obj => {
			$.log(`File ${obj.action}: ${fmt.warn(obj.file)}`)
		})

		.on("globs_no_match", (globs, opts) => {
			let str = `${fmt.warn("Warning:")} Source did not match any files!`
			str += `\n\t  Patterns:   ${JSON.stringify(globs)}`
			opts && (str += `\n\t  Options:    ${JSON.stringify(opts)}`)
			$.log(str)
		})

		.on("plugin_load", obj => {
			$.log(`Loading plugin ${fmt.title(obj.plugin)}`)
		})

		.on("plugin_load_error", str => {
			$.log(`Problem loading plugin: ${fmt.title(str)}`)
		})

		.on("plugin_rename", (old, nxt) => {
			$.log(`${fmt.title(old)} was renamed to ${fmt.title(nxt)} because its name was taken`)
		})

		.on("plugin_warning", obj => {
			$.log(`${fmt.warn(obj.plugin)} warned that ${fmt.warn(obj.warning)}`)
		})

		.on("plugin_error", obj => {
			process.exitCode = 1
			$.log(`${fmt.error(obj.plugin)} failed because ${fmt.error(obj.error)}`)
		})

		.on("tasks_force_object", () => {
			$.error("Invalid Tasks!")
			$.log("Custom `tasks` must be an `object`.")
			process.exit(1)
		})

		.on("task_error", (name, msg) => {
			$.log(`${fmt.error(name)} failed because ${fmt.error(msg)}`)
		})

		.on("task_start", str => {
			$.log(`Starting ${fmt.title(str)}`)
		})

		.on("task_complete", (str, time) => {
			const t = formatTime(time)
			$.log(`Finished ${fmt.complete(str)} in ${fmt.time(t)}`)
		})

		.on("task_not_found", str => {
			$.log(`${fmt.error(str)} not found in Flyfile.`)
			process.exit(1)
		})

		.on("serial_error", () => {
			$.error("Task chain was aborted!")
			process.exit(1)
		})
}
<commit_msg>fix 'fly_watch' output<commit_after>"use strict"

const fmt = require("./fmt")
const $ = require("./utils/logging")
const { formatTime } = require("./fn")

module.exports = function () {
	return this
		.on("fly_run", file => {
			$.log(`Flying with ${fmt.path(file)}`)
		})

		.on("flyfile_not_found", () => {
			$.log("Flyfile not found!")
			process.exit(1)
		})

		.on("fly_watch", () => {
			$.log(`${fmt.warn("Watching files...")}`)
		})

		.on("fly_watch_event", obj => {
			$.log(`File ${obj.action}: ${fmt.warn(obj.file)}`)
		})

		.on("globs_no_match", (globs, opts) => {
			let str = `${fmt.warn("Warning:")} Source did not match any files!`
			str += `\n\t  Patterns:   ${JSON.stringify(globs)}`
			opts && (str += `\n\t  Options:    ${JSON.stringify(opts)}`)
			$.log(str)
		})

		.on("plugin_load", obj => {
			$.log(`Loading plugin ${fmt.title(obj.plugin)}`)
		})

		.on("plugin_load_error", str => {
			$.log(`Problem loading plugin: ${fmt.title(str)}`)
		})

		.on("plugin_rename", (old, nxt) => {
			$.log(`${fmt.title(old)} was renamed to ${fmt.title(nxt)} because its name was taken`)
		})

		.on("plugin_warning", obj => {
			$.log(`${fmt.warn(obj.plugin)} warned that ${fmt.warn(obj.warning)}`)
		})

		.on("plugin_error", obj => {
			process.exitCode = 1
			$.log(`${fmt.error(obj.plugin)} failed because ${fmt.error(obj.error)}`)
		})

		.on("tasks_force_object", () => {
			$.error("Invalid Tasks!")
			$.log("Custom `tasks` must be an `object`.")
			process.exit(1)
		})

		.on("task_error", (name, msg) => {
			$.log(`${fmt.error(name)} failed because ${fmt.error(msg)}`)
		})

		.on("task_start", str => {
			$.log(`Starting ${fmt.title(str)}`)
		})

		.on("task_complete", (str, time) => {
			const t = formatTime(time)
			$.log(`Finished ${fmt.complete(str)} in ${fmt.time(t)}`)
		})

		.on("task_not_found", str => {
			$.log(`${fmt.error(str)} not found in Flyfile.`)
			process.exit(1)
		})

		.on("serial_error", () => {
			$.error("Task chain was aborted!")
			process.exit(1)
		})
}
<|endoftext|>


<commit_before>import React from 'react';
import PropTypes from 'prop-types';
import {autobind} from 'core-decorators';
import cx from 'classnames';
import {CompositeDisposable} from 'atom';

import StagingView from './staging-view';
import GitLogo from './git-logo';
import CommitViewController from '../controllers/commit-view-controller';
import EtchWrapper from './etch-wrapper';
import {isValidWorkdir} from '../helpers';

export default class GitTabView extends React.Component {
  static focus = {
    ...StagingView.focus,
    ...CommitViewController.focus,
  };

  static propTypes = {
    repository: PropTypes.object.isRequired,
    isLoading: PropTypes.bool.isRequired,

    lastCommit: PropTypes.object.isRequired,
    isMerging: PropTypes.bool,
    isRebasing: PropTypes.bool,
    isAmending: PropTypes.bool,
    hasUndoHistory: PropTypes.bool,
    currentBranch: PropTypes.object,
    unstagedChanges: PropTypes.arrayOf(PropTypes.object),
    stagedChanges: PropTypes.arrayOf(PropTypes.object),
    mergeConflicts: PropTypes.arrayOf(PropTypes.object),
    workingDirectoryPath: PropTypes.string,
    mergeMessage: PropTypes.string,
    fetchInProgress: PropTypes.bool,

    workspace: PropTypes.object.isRequired,
    commandRegistry: PropTypes.object.isRequired,
    grammars: PropTypes.object.isRequired,
    resolutionProgress: PropTypes.object.isRequired,
    notificationManager: PropTypes.object.isRequired,
    config: PropTypes.object.isRequired,
    project: PropTypes.object.isRequired,
    tooltips: PropTypes.object.isRequired,

    initializeRepo: PropTypes.func.isRequired,
    abortMerge: PropTypes.func.isRequired,
    commit: PropTypes.func.isRequired,
    prepareToCommit: PropTypes.func.isRequired,
    resolveAsOurs: PropTypes.func.isRequired,
    resolveAsTheirs: PropTypes.func.isRequired,
    undoLastDiscard: PropTypes.func.isRequired,
    attemptStageAllOperation: PropTypes.func.isRequired,
    attemptFileStageOperation: PropTypes.func.isRequired,
    discardWorkDirChangesForPaths: PropTypes.func.isRequired,
    openFiles: PropTypes.func.isRequired,
  };

  constructor(props, context) {
    super(props, context);

    this.subscriptions = new CompositeDisposable();

    this.refRoot = null;
    this.refStagingView = null;
    this.refCommitViewComponent = null;
  }

  componentDidMount() {
    this.subscriptions.add(
      this.props.commandRegistry.add(this.refRoot, {
        'tool-panel:unfocus': this.blur,
        'core:focus-next': this.advanceFocus,
        'core:focus-previous': this.retreatFocus,
      }),
    );
  }

  render() {
    if (this.props.repository.isTooLarge()) {
      return (

 { this.refRoot = c; }}>

              <GitLogo />

Too many changes

              The repository at {this.props.workingDirectoryPath} has too many changed files
              to display in Atom. Ensure that you have set up an appropriate .gitignore file.

      );
    } else if (this.props.repository.hasDirectory() &&
               !isValidWorkdir(this.props.repository.getWorkingDirectoryPath())) {
      return (

 { this.refRoot = c; }}>

              <GitLogo />

Unsupported directory

              Atom does not support managing Git repositories in your home or root directories.

      );
    } else if (this.props.repository.showGitTabInit()) {
      const inProgress = this.props.repository.showGitTabInitInProgress();
      const message = this.props.repository.hasDirectory() ?
        (
          Initialize {this.props.workingDirectoryPath} with a
          Git repository
        ) :
          Initialize a new project directory with a Git repository;

      return (

 { this.refRoot = c; }}>

              <GitLogo />

{message}

            <button onClick={this.initializeRepo} disabled={inProgress} className="btn btn-primary">
              {inProgress ? 'Creating repository...' : 'Create repository'}
            </button>

      );
    } else {
      const isLoading = this.props.fetchInProgress || this.props.repository.showGitTabLoading();

      return (

 { this.refRoot = c; }}>
          <EtchWrapper className="github-PanelEtchWrapper" ref={c => { this.refStagingView = c; }}>
            <StagingView
              commandRegistry={this.props.commandRegistry}
              notificationManager={this.props.notificationManager}
              workspace={this.props.workspace}
              stagedChanges={this.props.stagedChanges}
              unstagedChanges={this.props.unstagedChanges}
              mergeConflicts={this.props.mergeConflicts}
              workingDirectoryPath={this.props.workingDirectoryPath}
              resolutionProgress={this.props.resolutionProgress}
              openFiles={this.props.openFiles}
              discardWorkDirChangesForPaths={this.props.discardWorkDirChangesForPaths}
              attemptFileStageOperation={this.props.attemptFileStageOperation}
              attemptStageAllOperation={this.props.attemptStageAllOperation}
              undoLastDiscard={this.props.undoLastDiscard}
              abortMerge={this.props.abortMerge}
              resolveAsOurs={this.props.resolveAsOurs}
              resolveAsTheirs={this.props.resolveAsTheirs}
              lastCommit={this.props.lastCommit}
              isLoading={this.props.isLoading}
              isAmending={this.props.isAmending}
              hasUndoHistory={this.props.hasUndoHistory}
              isMerging={this.props.isMerging}
            />
          </EtchWrapper>
          <EtchWrapper ref={c => { this.refCommitViewController = c; }}>
            <CommitViewController
              tooltips={this.props.tooltips}
              config={this.props.config}
              stagedChangesExist={this.props.stagedChanges.length > 0}
              mergeConflictsExist={this.props.mergeConflicts.length > 0}
              prepareToCommit={this.props.prepareToCommit}
              commit={this.props.commit}
              abortMerge={this.props.abortMerge}
              branchName={''}
              workspace={this.props.workspace}
              commandRegistry={this.props.commandRegistry}
              notificationManager={this.props.notificationManager}
              grammars={this.props.grammars}
              mergeMessage={this.props.mergeMessage}
              isMerging={this.props.isMerging}
              isAmending={this.props.isAmending}
              isLoading={this.props.isLoading}
              lastCommit={this.props.lastCommit}
              repository={this.props.repository}
            />
          </EtchWrapper>

      );
    }
  }

  componentWillUnmount() {
    this.subscriptions.dispose();
  }

  @autobind
  initializeRepo(event) {
    event.preventDefault();
    let initPath = null;
    const activeEditor = this.props.workspace.getActiveTextEditor();
    if (activeEditor) {
      const [projectPath] = this.props.project.relativizePath(activeEditor.getPath());
      if (projectPath) {
        initPath = projectPath;
      }
    }
    this.props.initializeRepo(initPath);
  }

  rememberFocus(event) {
    let currentFocus = null;

    if (this.refs.stagingView) {
      currentFocus = this.refStagingView.getWrappedComponent().rememberFocus(event);
    }

    if (!currentFocus && this.refCommitViewController) {
      currentFocus = this.refCommitViewController.getWrappedComponent().rememberFocus(event);
    }

    return currentFocus;
  }

  setFocus(focus) {
    if (this.refStagingView) {
      if (this.refStagingView.getWrappedComponent().setFocus(focus)) {
        return true;
      }
    }

    if (this.refCommitViewController) {
      if (this.refCommitViewController.getWrappedComponent().setFocus(focus)) {
        return true;
      }
    }

    return false;
  }

  @autobind
  blur() {
    this.props.workspace.getActivePane().activate();
  }

  @autobind
  advanceFocus(evt) {
    if (!this.refStagingView.getWrappedComponent().activateNextList()) {
      if (this.refCommitViewController.getWrappedComponent().setFocus(GitTabView.focus.EDITOR)) {
        evt.stopPropagation();
      }
    } else {
      evt.stopPropagation();
    }
  }

  @autobind
  retreatFocus(evt) {
    const stagingView = this.refStagingView.getWrappedComponent();
    const commitViewController = this.refCommitViewController.getWrappedComponent();

    if (commitViewController.hasFocus()) {
      if (stagingView.activateLastList()) {
        this.setFocus(GitTabView.focus.STAGING);
        evt.stopPropagation();
      }
    } else {
      stagingView.activatePreviousList();
      evt.stopPropagation();
    }
  }

  async focusAndSelectStagingItem(filePath, stagingStatus) {
    await this.refStagingView.getWrappedComponent().quietlySelectItem(filePath, stagingStatus);
    this.setFocus(GitTabView.focus.STAGING);
  }

  hasFocus() {
    return this.refRoot.contains(document.activeElement);
  }

  @autobind
  quietlySelectItem(filePath, stagingStatus) {
    return this.refStagingView.getWrappedComponent().quietlySelectItem(filePath, stagingStatus);
  }
}
<commit_msg>Un-Etch-Wrap CommitViewController<commit_after>import React from 'react';
import PropTypes from 'prop-types';
import {autobind} from 'core-decorators';
import cx from 'classnames';
import {CompositeDisposable} from 'atom';

import StagingView from './staging-view';
import GitLogo from './git-logo';
import CommitViewController from '../controllers/commit-view-controller';
import EtchWrapper from './etch-wrapper';
import {isValidWorkdir} from '../helpers';

export default class GitTabView extends React.Component {
  static focus = {
    ...StagingView.focus,
    ...CommitViewController.focus,
  };

  static propTypes = {
    repository: PropTypes.object.isRequired,
    isLoading: PropTypes.bool.isRequired,

    lastCommit: PropTypes.object.isRequired,
    isMerging: PropTypes.bool,
    isRebasing: PropTypes.bool,
    isAmending: PropTypes.bool,
    hasUndoHistory: PropTypes.bool,
    currentBranch: PropTypes.object,
    unstagedChanges: PropTypes.arrayOf(PropTypes.object),
    stagedChanges: PropTypes.arrayOf(PropTypes.object),
    mergeConflicts: PropTypes.arrayOf(PropTypes.object),
    workingDirectoryPath: PropTypes.string,
    mergeMessage: PropTypes.string,
    fetchInProgress: PropTypes.bool,

    workspace: PropTypes.object.isRequired,
    commandRegistry: PropTypes.object.isRequired,
    grammars: PropTypes.object.isRequired,
    resolutionProgress: PropTypes.object.isRequired,
    notificationManager: PropTypes.object.isRequired,
    config: PropTypes.object.isRequired,
    project: PropTypes.object.isRequired,
    tooltips: PropTypes.object.isRequired,

    initializeRepo: PropTypes.func.isRequired,
    abortMerge: PropTypes.func.isRequired,
    commit: PropTypes.func.isRequired,
    prepareToCommit: PropTypes.func.isRequired,
    resolveAsOurs: PropTypes.func.isRequired,
    resolveAsTheirs: PropTypes.func.isRequired,
    undoLastDiscard: PropTypes.func.isRequired,
    attemptStageAllOperation: PropTypes.func.isRequired,
    attemptFileStageOperation: PropTypes.func.isRequired,
    discardWorkDirChangesForPaths: PropTypes.func.isRequired,
    openFiles: PropTypes.func.isRequired,
  };

  constructor(props, context) {
    super(props, context);

    this.subscriptions = new CompositeDisposable();

    this.refRoot = null;
    this.refStagingView = null;
    this.refCommitViewComponent = null;
  }

  componentDidMount() {
    this.subscriptions.add(
      this.props.commandRegistry.add(this.refRoot, {
        'tool-panel:unfocus': this.blur,
        'core:focus-next': this.advanceFocus,
        'core:focus-previous': this.retreatFocus,
      }),
    );
  }

  render() {
    if (this.props.repository.isTooLarge()) {
      return (

 { this.refRoot = c; }}>

              <GitLogo />

Too many changes

              The repository at {this.props.workingDirectoryPath} has too many changed files
              to display in Atom. Ensure that you have set up an appropriate .gitignore file.

      );
    } else if (this.props.repository.hasDirectory() &&
               !isValidWorkdir(this.props.repository.getWorkingDirectoryPath())) {
      return (

 { this.refRoot = c; }}>

              <GitLogo />

Unsupported directory

              Atom does not support managing Git repositories in your home or root directories.

      );
    } else if (this.props.repository.showGitTabInit()) {
      const inProgress = this.props.repository.showGitTabInitInProgress();
      const message = this.props.repository.hasDirectory() ?
        (
          Initialize {this.props.workingDirectoryPath} with a
          Git repository
        ) :
          Initialize a new project directory with a Git repository;

      return (

 { this.refRoot = c; }}>

              <GitLogo />

{message}

            <button onClick={this.initializeRepo} disabled={inProgress} className="btn btn-primary">
              {inProgress ? 'Creating repository...' : 'Create repository'}
            </button>

      );
    } else {
      const isLoading = this.props.fetchInProgress || this.props.repository.showGitTabLoading();

      return (

 { this.refRoot = c; }}>
          <EtchWrapper className="github-PanelEtchWrapper" ref={c => { this.refStagingView = c; }}>
            <StagingView
              commandRegistry={this.props.commandRegistry}
              notificationManager={this.props.notificationManager}
              workspace={this.props.workspace}
              stagedChanges={this.props.stagedChanges}
              unstagedChanges={this.props.unstagedChanges}
              mergeConflicts={this.props.mergeConflicts}
              workingDirectoryPath={this.props.workingDirectoryPath}
              resolutionProgress={this.props.resolutionProgress}
              openFiles={this.props.openFiles}
              discardWorkDirChangesForPaths={this.props.discardWorkDirChangesForPaths}
              attemptFileStageOperation={this.props.attemptFileStageOperation}
              attemptStageAllOperation={this.props.attemptStageAllOperation}
              undoLastDiscard={this.props.undoLastDiscard}
              abortMerge={this.props.abortMerge}
              resolveAsOurs={this.props.resolveAsOurs}
              resolveAsTheirs={this.props.resolveAsTheirs}
              lastCommit={this.props.lastCommit}
              isLoading={this.props.isLoading}
              isAmending={this.props.isAmending}
              hasUndoHistory={this.props.hasUndoHistory}
              isMerging={this.props.isMerging}
            />
          </EtchWrapper>
          <CommitViewController
            ref={c => { this.refCommitViewController = c; }}
            tooltips={this.props.tooltips}
            config={this.props.config}
            stagedChangesExist={this.props.stagedChanges.length > 0}
            mergeConflictsExist={this.props.mergeConflicts.length > 0}
            prepareToCommit={this.props.prepareToCommit}
            commit={this.props.commit}
            abortMerge={this.props.abortMerge}
            branchName={''}
            workspace={this.props.workspace}
            commandRegistry={this.props.commandRegistry}
            notificationManager={this.props.notificationManager}
            grammars={this.props.grammars}
            mergeMessage={this.props.mergeMessage}
            isMerging={this.props.isMerging}
            isAmending={this.props.isAmending}
            isLoading={this.props.isLoading}
            lastCommit={this.props.lastCommit}
            repository={this.props.repository}
          />

      );
    }
  }

  componentWillUnmount() {
    this.subscriptions.dispose();
  }

  @autobind
  initializeRepo(event) {
    event.preventDefault();
    let initPath = null;
    const activeEditor = this.props.workspace.getActiveTextEditor();
    if (activeEditor) {
      const [projectPath] = this.props.project.relativizePath(activeEditor.getPath());
      if (projectPath) {
        initPath = projectPath;
      }
    }
    this.props.initializeRepo(initPath);
  }

  rememberFocus(event) {
    let currentFocus = null;

    if (this.refs.stagingView) {
      currentFocus = this.refStagingView.getWrappedComponent().rememberFocus(event);
    }

    if (!currentFocus && this.refCommitViewController) {
      currentFocus = this.refCommitViewController.rememberFocus(event);
    }

    return currentFocus;
  }

  setFocus(focus) {
    if (this.refStagingView) {
      if (this.refStagingView.getWrappedComponent().setFocus(focus)) {
        return true;
      }
    }

    if (this.refCommitViewController) {
      if (this.refCommitViewController.setFocus(focus)) {
        return true;
      }
    }

    return false;
  }

  @autobind
  blur() {
    this.props.workspace.getActivePane().activate();
  }

  @autobind
  advanceFocus(evt) {
    if (!this.refStagingView.getWrappedComponent().activateNextList()) {
      if (this.refCommitViewController.setFocus(GitTabView.focus.EDITOR)) {
        evt.stopPropagation();
      }
    } else {
      evt.stopPropagation();
    }
  }

  @autobind
  retreatFocus(evt) {
    const stagingView = this.refStagingView.getWrappedComponent();
    const commitViewController = this.refCommitViewController;

    if (commitViewController.hasFocus()) {
      if (stagingView.activateLastList()) {
        this.setFocus(GitTabView.focus.STAGING);
        evt.stopPropagation();
      }
    } else {
      stagingView.activatePreviousList();
      evt.stopPropagation();
    }
  }

  async focusAndSelectStagingItem(filePath, stagingStatus) {
    await this.refStagingView.getWrappedComponent().quietlySelectItem(filePath, stagingStatus);
    this.setFocus(GitTabView.focus.STAGING);
  }

  hasFocus() {
    return this.refRoot.contains(document.activeElement);
  }

  @autobind
  quietlySelectItem(filePath, stagingStatus) {
    return this.refStagingView.getWrappedComponent().quietlySelectItem(filePath, stagingStatus);
  }
}
<|endoftext|>


<commit_before>/**
 * Created with JetBrains WebStorm.
 * User: wlyonpr
 * Date: 7/26/13
 * Time: 4:03 PM
 * To change this template use File | Settings | File Templates.
 */
<commit_msg>Removing old file<commit_after><|endoftext|>


<commit_before>'use babel'
/* globals atom */

import { Emitter } from 'atom'
import { View } from 'atom-space-pen-views'
import { logo } from '../../assets/svgs'
import getKeybinding from '../utils/get-keybinding'

/* when this file is run the keybindings aren't ready yet
 that's why giving atom some time to prepare before we ask
 for the keybinding */
setTimeout(() => {
  let keybinding = getKeybinding('command-palette:toggle')
  descriptions.ALL_GOOD.description = descriptions.ALL_GOOD.description.replace('!!!!', keybinding)
}, 3000)

const descriptions = {
  NOT_INSTALLED: {
    title: 'kd is missing',
    description: 'Please open a terminal window and install it with the following commands and come back once done. (mac/linux only)'
  },
  NOT_LOGGEDIN: {
    title: 'Login/Register',
    description: 'You are not logged in, please log in with the following commands and come back.'
  },
  DAEMON_NOT_INSTALLED: {
    title: 'Daemon is missing',
    description: 'It seems like the kd binary is installed but its daemon is missing, please install it with the following command.'
  },
  DAEMON_STOPPED: {
    title: 'Daemon is not running',
    description: 'kd daemon is not running please run it with the following command:'
  },
  ALL_GOOD: {
    title: 'kd is up & running',
    description: `The daemon is running. You're logged in! <br><br>Now you can open the command palette(!!!!) and type 'kd:' to see the available kd commands`
  }
}

const success = {
  NOT_INSTALLED: 'kd is installed',
  NOT_LOGGEDIN: 'you are logged in',
  DAEMON_NOT_INSTALLED: 'kd daemon is installed',
  DAEMON_STOPPED: 'kd daemon is running'
}

const helpers = {
  NOT_INSTALLED: [
    'brew tap rjeczalik/kd',
    'brew install kd --devel',
    'sudo kd daemon install --team <yourteam> --baseurl https://koding.com'
  ],
  NOT_LOGGEDIN: [
    'kd auth login --team <yourteam>'
  ],
  DAEMON_NOT_INSTALLED: [
    'sudo kd daemon install --team <yourteam>'
  ],
  DAEMON_STOPPED: [
    'sudo kd daemon restart'
  ]
}

export default class KDHelpView extends View {

  static content (data = {}) {
    this.div(() => {
      if (!data.mini) {
        this.div({ class: 'kd-help-view--logo' }, () => { this.raw(logo) })
      }
      this.div({ outlet: 'content', click: 'click' }, () => {
        this.raw("
checking kd…
")
      })
    })
  }

  setData (data = {}) {
    this.__data = data
    return data
  }

  getData () {
    return this.__data
  }

  initialize (data) {
    let { prompt, succeeded } = data
    this.setData(data)
    this.emitter = new Emitter()
    if (prompt) {
      this.setContent(prompt)
    }
    if (!prompt && succeeded.length) {
      succeeded.forEach(step => {
        this.appendContent(step)
      })
    }
  }

  setContent (prompt) {
    this.content.html('')
    let commandsHTML = ''
    if (helpers[prompt]) {
      for (let command of Array.from(helpers[prompt])) {
        commandsHTML += `<span class='icon icon-clippy clippy' data-command='${command}'></span><code class='clippy'>${command}</code><br>`
      }
    }
    this.content.append(`<h2>${descriptions[prompt].title}</h2>`)
    this.content.append(`<p>${descriptions[prompt].description}</p>`)
    if (commandsHTML) {
      this.content.append(`<pre>${commandsHTML}</pre>`)
    }
  }

  click (event) {
    if (event.target.classList.contains('clippy')) {
      return this.copyToClipboard(event)
    }
  }

  copyToClipboard (event) {
    let command = event.target.dataset.command || event.target.innerHTML
    atom.clipboard.write(command)
    atom.notifications.add('info', 'Command copied to the clipboard!', {
      icon: 'clippy',
      description: `\`${command}\``
    })
  }

  appendContent (step) {
    if (success[step]) {
      this.content.append(`<div class='icon icon-check'>${success[step]}</div>`)
    }
  }

}
<commit_msg>minor copy change<commit_after>'use babel'
/* globals atom */

import { Emitter } from 'atom'
import { View } from 'atom-space-pen-views'
import { logo } from '../../assets/svgs'
import getKeybinding from '../utils/get-keybinding'

/* when this file is run the keybindings aren't ready yet
 that's why giving atom some time to prepare before we ask
 for the keybinding */
setTimeout(() => {
  let keybinding = getKeybinding('command-palette:toggle')
  descriptions.ALL_GOOD.description = descriptions.ALL_GOOD.description.replace('!!!!', keybinding)
}, 3000)

const descriptions = {
  NOT_INSTALLED: {
    title: 'kd is missing',
    description: 'Please open a terminal window and install it with the following commands and come back once done. (mac/linux only)'
  },
  NOT_LOGGEDIN: {
    title: 'Login/Register',
    description: 'You are not logged in, please log in with the following commands and come back.'
  },
  DAEMON_NOT_INSTALLED: {
    title: 'Daemon is missing',
    description: 'It seems like the kd binary is installed but its daemon is missing, please install it with the following command.'
  },
  DAEMON_STOPPED: {
    title: 'Daemon is not running',
    description: 'kd daemon is not running please run it with the following command:'
  },
  ALL_GOOD: {
    title: 'kd is up & running',
    description: `The daemon is running. You're logged in! <br><br>Now you can open the command palette(<code>!!!!</code>) and type <code>kd</code> to see the available commands.`
  }
}

const success = {
  NOT_INSTALLED: 'kd is installed',
  NOT_LOGGEDIN: 'you are logged in',
  DAEMON_NOT_INSTALLED: 'kd daemon is installed',
  DAEMON_STOPPED: 'kd daemon is running'
}

const helpers = {
  NOT_INSTALLED: [
    'brew tap rjeczalik/kd',
    'brew install kd --devel',
    'sudo kd daemon install --team <yourteam> --baseurl https://koding.com'
  ],
  NOT_LOGGEDIN: [
    'kd auth login --team <yourteam>'
  ],
  DAEMON_NOT_INSTALLED: [
    'sudo kd daemon install --team <yourteam>'
  ],
  DAEMON_STOPPED: [
    'sudo kd daemon restart'
  ]
}

export default class KDHelpView extends View {

  static content (data = {}) {
    this.div(() => {
      if (!data.mini) {
        this.div({ class: 'kd-help-view--logo' }, () => { this.raw(logo) })
      }
      this.div({ outlet: 'content', click: 'click' }, () => {
        this.raw("
checking kd…
")
      })
    })
  }

  setData (data = {}) {
    this.__data = data
    return data
  }

  getData () {
    return this.__data
  }

  initialize (data) {
    let { prompt, succeeded } = data
    this.setData(data)
    this.emitter = new Emitter()
    if (prompt) {
      this.setContent(prompt)
    }
    if (!prompt && succeeded.length) {
      succeeded.forEach(step => {
        this.appendContent(step)
      })
    }
  }

  setContent (prompt) {
    this.content.html('')
    let commandsHTML = ''
    if (helpers[prompt]) {
      for (let command of Array.from(helpers[prompt])) {
        commandsHTML += `<span class='icon icon-clippy clippy' data-command='${command}'></span><code class='clippy'>${command}</code><br>`
      }
    }
    this.content.append(`<h2>${descriptions[prompt].title}</h2>`)
    this.content.append(`<p>${descriptions[prompt].description}</p>`)
    if (commandsHTML) {
      this.content.append(`<pre>${commandsHTML}</pre>`)
    }
  }

  click (event) {
    if (event.target.classList.contains('clippy')) {
      return this.copyToClipboard(event)
    }
  }

  copyToClipboard (event) {
    let command = event.target.dataset.command || event.target.innerHTML
    atom.clipboard.write(command)
    atom.notifications.add('info', 'Command copied to the clipboard!', {
      icon: 'clippy',
      description: `\`${command}\``
    })
  }

  appendContent (step) {
    if (success[step]) {
      this.content.append(`<div class='icon icon-check'>${success[step]}</div>`)
    }
  }

}
<|endoftext|>


<commit_before>module.exports = grammar({
  name: 'ruby',

  rules: {
    program: $ => $._compound_statement,

	_compound_statement: $ => seq($._statement, rep(seq($._terminator, $._expression)), optional($._terminator)),

	_statement: $ => choice($._expression),
	_expression: $ => choice($._argument),

	_argument: $ => choice($._primary),

	_primary: $ => choice($._variable),

	_variable: $ => choice($.identifier , 'nil', 'self'),

	identifier: $ => seq(rep(choice('@', '$')), /[a-zA-Z_][a-zA-Z0-9_]*/),

    _line_break: $ => '\n',
	_terminator: $ => choice($._line_break, ';'),
  }
});
<commit_msg>Define a dubious comment rule.<commit_after>module.exports = grammar({
  name: 'ruby',

  rules: {
    program: $ => $._compound_statement,

	_compound_statement: $ => seq($._statement, rep(seq($._terminator, $._expression)), optional($._terminator)),

	_statement: $ => choice($._expression),
	_expression: $ => choice($._argument),

	_argument: $ => choice($._primary),

	_primary: $ => choice($._variable),

	_variable: $ => choice($.identifier , 'nil', 'self'),

	identifier: $ => seq(rep(choice('@', '$')), /[a-zA-Z_][a-zA-Z0-9_]*/),

	comment: $ => seq('#', /.*/),

    _line_break: $ => '\n',
	_terminator: $ => choice($._line_break, ';'),
  }
});
<|endoftext|>


<commit_before>'use strict';

/**
this module provides functions for reading and writing local files,
as well as functions for preparing data that is about to be written
*/

// Node.js built-ins

const path = require('path');

// foreign modules

const pify = require('pify');
const globp = pify(require('glob'));
const loadJson = require('load-json-file');
const memoize = require('lodash.memoize');
const readJsonFiles = require('@blinkmobile/json-as-files').readData;
const rimrafp = pify(require('rimraf'));
const writeJson = require('write-json-file');
const writeJsonFiles = require('@blinkmobile/json-as-files').writeData;

// local modules

const asyncp = require('./utils/asyncp');
const content = require('./content.js');

// this module

function deleteInteraction (options) {
  return rimrafp(path.join(options.cwd, 'interactions', options.name));
}

function listInteractions (options) {
  const cwd = options.cwd;
  return globp('*/*.json', {
    cwd: path.join(cwd, 'interactions')
  })
    .then((files) => {
      return files
        // keep just the results that match NAME/NAME.json pattern
        .filter((x) => /^([^\\\s]+)\/\1\.json$/.test(x))
        // then just give us the names
        .map((x) => x.split('/')[0]);
    })
    .then((names) => asyncp.mapSeries(names, asyncp.asyncify((name) => {
      return readInteraction({ cwd, name })
        .then((data) => ({ id: data.id, name: data.name }));
    })));
}

function readAnswerSpace (options) {
  return readJsonFiles({ filePath: path.join(options.cwd, 'answerSpace.json') })
    .then((data) => fixAnswerSpace(data));
}

const readCachedAnswerSpace = memoize(readAnswerSpace);

function readInteraction (options) {
  const filePath = path.join(options.cwd, 'interactions', options.name, `${options.name}.json`);
  return readJsonFiles({ filePath })
    .then((data) => fixInteraction(data));
}

function writeAnswerSpace (options) {
  const filePath = path.join(options.cwd, 'answerSpace.json');
  const defaultPlaceholders = content.defaultAnswerSpace('answerSpace');

  return writeMergedPlaceholders(filePath, defaultPlaceholders)
    .then(() => {
      const data = Object.assign({}, options.data);
      content.fixAnswerSpace(data);
      // persist the real data, honoring the $file placeholders
      return writeJsonFiles({ data, filePath });
    });
}

function writeInteraction (options) {
  const cwd = options.cwd;
  const name = options.name;
  const filePath = path.join(cwd, 'interactions', name, `${name}.json`);
  const defaultPlaceholders = content.defaultInteraction(name);

  return writeMergedPlaceholders(filePath, defaultPlaceholders)
    .then(() => {
      const data = Object.assign({}, options.data);
      content.fixInteraction(data);
      // persist the real data, honoring the $file placeholders
      return writeJsonFiles({ data, filePath });
    });
}

function writeMergedPlaceholders (filePath, defaults) {
  return loadJson(filePath)
    .catch(() => ({})) // default to empty Object
    .then((existing) => content.mergePlaceholders(existing, defaults))
    .then((merged) => writeJson(filePath, merged));
}

module.exports = {
  deleteInteraction,
  listInteractions,
  readAnswerSpace,
  readCachedAnswerSpace,
  readInteraction,
  writeAnswerSpace,
  writeInteraction
};
<commit_msg>BC-34 # make `listInteractions()` more efficient<commit_after>'use strict';

/**
this module provides functions for reading and writing local files,
as well as functions for preparing data that is about to be written
*/

// Node.js built-ins

const path = require('path');

// foreign modules

const pify = require('pify');
const globp = pify(require('glob'));
const loadJson = require('load-json-file');
const memoize = require('lodash.memoize');
const readJsonFiles = require('@blinkmobile/json-as-files').readData;
const rimrafp = pify(require('rimraf'));
const writeJson = require('write-json-file');
const writeJsonFiles = require('@blinkmobile/json-as-files').writeData;

// local modules

const asyncp = require('./utils/asyncp');
const content = require('./content.js');

// this module

function deleteInteraction (options) {
  return rimrafp(path.join(options.cwd, 'interactions', options.name));
}

function listInteractions (options) {
  const cwd = options.cwd;
  return globp('*/*.json', {
    cwd: path.join(cwd, 'interactions')
  })
    .then((files) => {
      return files
        // keep just the results that match NAME/NAME.json pattern
        .filter((x) => /^([^\\\s]+)\/\1\.json$/.test(x))
        // then just give us the names
        .map((x) => x.split('/')[0]);
    })
    .then((names) => asyncp.mapSeries(names, asyncp.asyncify((name) => {
      return readInteraction({ cwd, name, raw: true })
        .then((data) => ({ id: data.id, name: data.name }));
    })));
}

function readAnswerSpace (options) {
  const readFn = options.raw ? (options) => loadJson(options.filePath) : readJsonFiles;
  return readFn({ filePath: path.join(options.cwd, 'answerSpace.json') })
    .then((data) => content.fixAnswerSpace(data));
}

const readCachedAnswerSpace = memoize(readAnswerSpace);

function readInteraction (options) {
  const readFn = options.raw ? (options) => loadJson(options.filePath) : readJsonFiles;
  const filePath = path.join(options.cwd, 'interactions', options.name, `${options.name}.json`);
  return readFn({ filePath })
    .then((data) => content.fixInteraction(data));
}

function writeAnswerSpace (options) {
  const filePath = path.join(options.cwd, 'answerSpace.json');
  const defaultPlaceholders = content.defaultAnswerSpace('answerSpace');

  return writeMergedPlaceholders(filePath, defaultPlaceholders)
    .then(() => {
      const data = Object.assign({}, options.data);
      content.fixAnswerSpace(data);
      // persist the real data, honoring the $file placeholders
      return writeJsonFiles({ data, filePath });
    });
}

function writeInteraction (options) {
  const cwd = options.cwd;
  const name = options.name;
  const filePath = path.join(cwd, 'interactions', name, `${name}.json`);
  const defaultPlaceholders = content.defaultInteraction(name);

  return writeMergedPlaceholders(filePath, defaultPlaceholders)
    .then(() => {
      const data = Object.assign({}, options.data);
      content.fixInteraction(data);
      // persist the real data, honoring the $file placeholders
      return writeJsonFiles({ data, filePath });
    });
}

function writeMergedPlaceholders (filePath, defaults) {
  return loadJson(filePath)
    .catch(() => ({})) // default to empty Object
    .then((existing) => content.mergePlaceholders(existing, defaults))
    .then((merged) => writeJson(filePath, merged));
}

module.exports = {
  deleteInteraction,
  listInteractions,
  readAnswerSpace,
  readCachedAnswerSpace,
  readInteraction,
  writeAnswerSpace,
  writeInteraction
};
<|endoftext|>


<commit_before>const PREC = {
  AND: -1,
  OR: -1,
  NOT: 5,
  DEFINED: 10,
  ASSIGN: 15,
  CONDITIONAL: 20,
  RANGE: 25,
  BOOLEAN_OR: 30,
  BOOLEAN_AND: 35,
  RELATIONAL: 40,
  COMPARISON: 45,
  BITWISE_OR: 50,
  BITWISE_AND: 55,
  SHIFT: 60,
  ADDITIVE: 65,
  MULTIPLICATIVE: 70,
  UNARY_MINUS: 75,
  EXPONENTIAL: 80,
  COMPLEMENT: 85,
  LITERAL: 100,
};

const unbalancedDelimiters = '!@#$%^&*)]}>|\\=/+-~`\'",.?:;_';
const identifierPattern = /[a-zA-Z_][a-zA-Z0-9_]*/;
const operators = ['..', '|', '^', '&', '<=>', '==', '===', '=~', '>', '>=', '<', '<=', '+', '-', '*', '/', '%', '**', '<<', '>>', '~', '+@', '-@', '[]', '[]='];

module.exports = grammar({
  name: 'ruby',

  extras: $ => [
    $.comment,
    $._line_break,
    /[ \t\r]/
  ],

  rules: {
    program: $ => sep($._statement, $._terminator),

    _statement: $ => choice(
      $._declaration,
      seq($._call, "do", optional("|", commaSep($._block_variable), "|"), sep($._statement, $._terminator), "end"),
      seq("undef", $._function_name),
      seq("alias", $._function_name, $._function_name),
      $.while_statement,
      $.until_statement,
      $.if_statement,
      $.unless_statement,
      $.for_statement,
      $.begin_statement,
      $.return_statement,
      $.if_modifier,
      $.unless_modifier,
      $.while_modifier,
      $.until_modifier,
      $._expression
    ),

    _declaration: $ => choice(
      $.method_declaration,
      $.class_declaration,
      $.module_declaration
    ),

    method_declaration: $ => seq(
      "def", $._function_name, choice(seq("(", optional($.argument_list), ")"), seq(optional($.argument_list), $._terminator)),
      sep($._statement, $._terminator),
      "end"
    ),

    argument_list: $ => commaSep1(seq(optional(choice("*", "&")), $.identifier)),

    class_declaration: $ => seq("class", $.identifier, optional(seq("<", sep1($.identifier, "::"))), $._terminator, sep($._statement, $._terminator), "end"),

    module_declaration: $ => seq("module", $.identifier, $._terminator, sep($._statement, $._terminator), "end"),

    while_statement: $ => seq("while", $.condition, $._statement_block),
    until_statement: $ => seq("until", $.condition, $._statement_block),
    if_statement: $ => seq("if", $.condition, $._then_elsif_else_block),
    unless_statement: $ => seq("unless", $.condition, $._then_else_block),
    for_statement: $ => seq("for", $._lhs, "in", $._expression, $._statement_block),
    begin_statement: $ => seq(
      "begin",
      sep($._statement, $._terminator),
      repeat($.rescue_block),
      optional($.else_block),
      optional($.ensure_block),
      "end"
    ),

    return_statement: $ => seq("return", optional($._expression)),

    if_modifier: $ => seq($._statement, "if", $._expression),
    unless_modifier: $ => seq($._statement, "unless", $._expression),
    while_modifier: $ => seq($._statement, "while", $._expression),
    until_modifier: $ => seq($._statement, "until", $._expression),

    condition: $ => $._expression,

    _statement_block: $ => choice(
      $._do_block,
      seq($._terminator, sep($._statement, $._terminator), "end")
    ),
    _do_block: $ => seq("do", sep($._statement, $._terminator), "end"),

    then_block: $ => seq(choice("then", $._terminator), sep($._statement, $._terminator)),
    else_block: $ => seq("else", sep($._statement, $._terminator)),
    rescue_block: $ => seq("rescue", commaSep($._argument), choice("do", $._terminator), sep($._statement, $._terminator)),
    ensure_block: $ => seq("ensure", sep($._statement, $._terminator)),

    _then_else_block: $ => seq($.then_block, optional($.else_block), "end"),
    _then_elsif_else_block: $ => seq(
      $.then_block,
      repeat(seq(
        "elsif", $.condition,
        $.then_block
      )),
      optional($.else_block),
      "end"
    ),

    _call: $ => choice($._function_call, $._command),

    _call_arguments: $ => choice(
      commaSep1($._argument),
      $._command
    ),

    _command: $ => choice(
      seq("super", $._call_arguments)
    ),
    _function_call: $ => choice("super"),

    _expression: $ => choice(
      $._argument,
      $.yield,
      $.and,
      $.or,
      $.not,
      $.defined,
      $.assignment,
      $.conditional,
      $.range,
      $.boolean_or,
      $.boolean_and,
      $.relational,
      $.comparison,
      $.bitwise_or,
      $.bitwise_and,
      $.shift,
      $.additive,
      $.multiplicative,
      $.unary_minus,
      $.exponential,
      $.complement,
      $._literal
    ),

    _argument: $ => choice($._primary),

    _primary: $ => choice(
      seq("(", sep($._statement, $._terminator), ")"),
      $._lhs
    ),

    scope_resolution_expression: $ => seq(optional($._primary), '::', $.identifier),
    subscript_expression: $ => seq($._primary, "[", commaSep($._argument), "]"),
    member_access: $ => seq($._primary, ".", $.identifier),
    yield: $ => seq("yield", optional($._expression)),

    and: $ => prec.left(PREC.AND, seq($._expression, "and", $._expression)),
    or: $ => prec.left(PREC.OR, seq($._expression, "or", $._expression)),
    not: $ => prec.right(PREC.NOT, seq("not", $._expression)),
    defined: $ => prec(PREC.DEFINED, seq("defined?", $._expression)),
    assignment: $ => prec.right(PREC.ASSIGN, seq($._lhs, '=', $._expression)),
    conditional: $ => prec.right(PREC.CONDITIONAL, seq($._expression, '?', $._expression, ':', $._expression)),
    range: $ => prec.right(PREC.RANGE, seq($._expression, choice('..', '...'), $._expression)),

    boolean_or: $ => prec.left(PREC.BOOLEAN_OR, seq($._expression, '||', $._expression)),
    boolean_and: $ => prec.left(PREC.BOOLEAN_OR, seq($._expression, '&&', $._expression)),

    relational: $ => prec.right(PREC.RELATIONAL, seq($._expression, choice('==', '!=', '===', '<=>', '=~', '!~'), $._expression)),
    comparison: $ => prec.left(PREC.COMPARISON, seq($._expression, choice('<', '<=', '>', '>='), $._expression)),

    bitwise_or: $ => prec.left(PREC.BITWISE_OR, seq($._expression, choice('^', '|'), $._expression)),
    bitwise_and: $ => prec.left(PREC.BITWISE_AND, seq($._expression, '&', $._expression)),
    shift: $ => prec.left(PREC.SHIFT, seq($._expression, choice('<<', '>>'), $._expression)),

    additive: $ => prec.left(PREC.ADDITIVE, seq($._expression, choice('-', '+'), $._expression)),
    multiplicative: $ => prec.left(PREC.MULTIPLICATIVE, seq($._expression, choice('*', '/', '%'), $._expression)),

    unary_minus: $ => prec.right(PREC.UNARY_MINUS, seq('-', $._expression)),

    exponential: $ => prec.right(PREC.EXPONENTIAL, seq($._expression, '**', $._expression)),

    complement: $ => prec.right(PREC.COMPLEMENT, seq(choice('!', '~', '+'), $._expression)),

    _block_variable: $ => choice($._lhs, $._mlhs),
    _mlhs: $ => choice(
      seq(commaSep1($._mlhs_item), optional(seq("*", optional($._lhs)))),
      seq("*", optional($._lhs))
    ),
    _mlhs_item: $ => choice($._lhs, seq("(", $._mlhs, ")")),
    _lhs: $ => choice(
      $._variable,
      $.scope_resolution_expression,
      $.subscript_expression,
      $.member_access
    ),
    _variable: $ => choice($.identifier , 'self'),

    identifier: $ => token(seq(repeat(choice('@', '$')), identifierPattern)),

    comment: $ => token(choice(
      seq('#', /.*/),
      seq(
        '=begin\n',
        repeat(/.*\n/),
        '=end\n'
      )
    )),

    _literal: $ => choice(
      $.symbol,
      $.integer,
      $.float,
      $.boolean,
      $.nil,
      $.string,
      $.subshell,
      $.array,
      $.regex
    ),

    symbol: $ => choice(
      token(seq(':', choice(identifierPattern, choice.apply(null, operators)))),
      seq(":'", $._single_quoted_continuation),
      seq(':"', $._double_quoted_continuation),
      choice.apply(null, unbalancedDelimiters.split('').map(d => stringBody('%s' + d, d))),
      seq(/%s/, $._uninterpolated_angle),
      seq(/%s/, $._uninterpolated_bracket),
      seq(/%s/, $._uninterpolated_paren),
      seq(/%s/, $._uninterpolated_brace)
    ),

    integer: $ => (/0b[01](_?[01])*|0[oO]?[0-7](_?[0-7])*|(0d)?\d(_?\d)*|0x[0-9a-fA-F](_?[0-9a-fA-F])*/),
    float: $ => (/\d(_?\d)*\.\d(_?\d)*([eE]\d(_?\d)*)?/),
    boolean: $ => choice('true', 'false', 'TRUE', 'FALSE'),
    nil: $ => choice('nil', 'NIL'),

    string: $ => choice(
      seq("'", $._single_quoted_continuation),
      seq('"', $._double_quoted_continuation),
      choice.apply(null, unbalancedDelimiters.split('').map(d => stringBody(RegExp('%(Q|)\\' + d), d, $.interpolation))),
      seq(/%Q?/, $._interpolated_angle),
      seq(/%Q?/, $._interpolated_bracket),
      seq(/%Q?/, $._interpolated_paren),
      seq(/%Q?/, $._interpolated_brace),
      choice.apply(null, unbalancedDelimiters.split('').map(d => stringBody('%q' + d, d))),
      seq('%q', $._uninterpolated_angle),
      seq('%q', $._uninterpolated_bracket),
      seq('%q', $._uninterpolated_paren),
      seq('%q', $._uninterpolated_brace)
    ),
    _single_quoted_continuation: $ => stringBody(blank(), "'"),
    _double_quoted_continuation: $ => stringBody(blank(), '"', $.interpolation),

    _interpolated_angle: $ => balancedStringBody($._interpolated_angle, '<', '>', $.interpolation),
    _interpolated_bracket: $ => balancedStringBody($._interpolated_bracket, '[', ']', $.interpolation),
    _interpolated_paren: $ => balancedStringBody($._interpolated_paren, '(', ')', $.interpolation),
    _interpolated_brace: $ => balancedStringBody($._interpolated_brace, '{', '}', $.interpolation),
    _uninterpolated_angle: $ => balancedStringBody($._uninterpolated_angle, '<', '>'),
    _uninterpolated_bracket: $ => balancedStringBody($._uninterpolated_bracket, '[', ']'),
    _uninterpolated_paren: $ => balancedStringBody($._uninterpolated_paren, '(', ')'),
    _uninterpolated_brace: $ => balancedStringBody($._uninterpolated_brace, '{', '}'),
    interpolation: $ => seq(token(prec(PREC.LITERAL, '#{')), $._expression, '}'),

    subshell: $ => choice(
      stringBody('`', '`'),
      choice.apply(null, unbalancedDelimiters.split('').map(d => stringBody('%x' + d, d, $.interpolation))),
      seq('%x', $._interpolated_angle),
      seq('%x', $._interpolated_bracket),
      seq('%x', $._interpolated_paren),
      seq('%x', $._interpolated_brace)
    ),

    array: $ => choice(
      seq('[', $._array_items, ']'),
      choice.apply(null, unbalancedDelimiters.split('').map(d => stringBody(RegExp('%[wi]\\' + d), d))),
      seq(/%[wi]/, $._uninterpolated_angle),
      seq(/%[wi]/, $._uninterpolated_bracket),
      seq(/%[wi]/, $._uninterpolated_paren),
      seq(/%[wi]/, $._uninterpolated_brace),
      choice.apply(null, unbalancedDelimiters.split('').map(d => stringBody(RegExp('%[WI]\\' + d), d, $.interpolation))),
      seq(/%[WI]/, $._interpolated_angle),
      seq(/%[WI]/, $._interpolated_bracket),
      seq(/%[WI]/, $._interpolated_paren),
      seq(/%[WI]/, $._interpolated_brace)
    ),
    _array_items: $ => optional(seq($._expression, optional(seq(',', $._array_items)))),

    regex: $ => prec(PREC.LITERAL, choice(
      regexBody('/', '/', $.interpolation),
      choice.apply(null, unbalancedDelimiters.split('').map(d => regexBody('%r' + d, d, $.interpolation)))
    )),
    _regex_interpolated_angle: $ => regexBody('<', '>', $.interpolation, $._regex_interpolated_angle),
    _regex_interpolated_bracket: $ => regexBody('[', ']', $.interpolation, $._regex_interpolated_bracket),
    _regex_interpolated_paren: $ => regexBody('(', ')', $.interpolation, $._regex_interpolated_paren),
    _regex_interpolated_brace: $ => regexBody('{', '}', $.interpolation, $._regex_interpolated_brace),

    _function_name: $ => choice($.identifier, choice.apply(null, operators)),

    _line_break: $ => '\n',
    _terminator: $ => choice($._line_break, ';'),
  }
});

/// Describes the body of a string literal bounded by `open` and `close`, and optionally containing (potentially recursive) references to `insert`.
function stringBody (open, close, insert) {
  var contents = [ /\\./, RegExp('[^\\\\\\' + close + ']') ];
  if (typeof insert !== 'undefined') contents.push(insert);
  return seq(open, repeat(choice.apply(null, contents)), token(prec(PREC.LITERAL, close)));
}

function balancedStringBody (me, open, close, insert) {
  var contents = [ /\\./, me, RegExp('[^\\\\\\' + open + '\\' + close + ']') ];
  if (typeof insert !== 'undefined') contents.push(insert);
  return seq(open, repeat(choice.apply(null, contents)), close);
}

function regexBody (open, close, interpolation, me) {
  var contents = [
    RegExp('\\[[^\\]\\n]*\\]|\\\\.|[^\\' + close + '\\\\\\[\\n]'),
    interpolation
  ];
  if (typeof me !== 'undefined') contents.push(me);
  return seq(open, repeat(choice.apply(null, contents)), token(prec(PREC.LITERAL, RegExp('\\' + close + '[a-z]*'))));
}

function sep1 (rule, separator) {
  return seq(rule, repeat(seq(separator, rule)));
}

function sep (rule, separator) {
  return optional(sep1(rule, separator));
}

function commaSep1 (rule) {
  return sep1(rule, ',')
}

function commaSep (rule) {
  return optional(commaSep1(rule));
}
<commit_msg>Parse balanced interpolated regexps.<commit_after>const PREC = {
  AND: -1,
  OR: -1,
  NOT: 5,
  DEFINED: 10,
  ASSIGN: 15,
  CONDITIONAL: 20,
  RANGE: 25,
  BOOLEAN_OR: 30,
  BOOLEAN_AND: 35,
  RELATIONAL: 40,
  COMPARISON: 45,
  BITWISE_OR: 50,
  BITWISE_AND: 55,
  SHIFT: 60,
  ADDITIVE: 65,
  MULTIPLICATIVE: 70,
  UNARY_MINUS: 75,
  EXPONENTIAL: 80,
  COMPLEMENT: 85,
  LITERAL: 100,
};

const unbalancedDelimiters = '!@#$%^&*)]}>|\\=/+-~`\'",.?:;_';
const identifierPattern = /[a-zA-Z_][a-zA-Z0-9_]*/;
const operators = ['..', '|', '^', '&', '<=>', '==', '===', '=~', '>', '>=', '<', '<=', '+', '-', '*', '/', '%', '**', '<<', '>>', '~', '+@', '-@', '[]', '[]='];

module.exports = grammar({
  name: 'ruby',

  extras: $ => [
    $.comment,
    $._line_break,
    /[ \t\r]/
  ],

  rules: {
    program: $ => sep($._statement, $._terminator),

    _statement: $ => choice(
      $._declaration,
      seq($._call, "do", optional("|", commaSep($._block_variable), "|"), sep($._statement, $._terminator), "end"),
      seq("undef", $._function_name),
      seq("alias", $._function_name, $._function_name),
      $.while_statement,
      $.until_statement,
      $.if_statement,
      $.unless_statement,
      $.for_statement,
      $.begin_statement,
      $.return_statement,
      $.if_modifier,
      $.unless_modifier,
      $.while_modifier,
      $.until_modifier,
      $._expression
    ),

    _declaration: $ => choice(
      $.method_declaration,
      $.class_declaration,
      $.module_declaration
    ),

    method_declaration: $ => seq(
      "def", $._function_name, choice(seq("(", optional($.argument_list), ")"), seq(optional($.argument_list), $._terminator)),
      sep($._statement, $._terminator),
      "end"
    ),

    argument_list: $ => commaSep1(seq(optional(choice("*", "&")), $.identifier)),

    class_declaration: $ => seq("class", $.identifier, optional(seq("<", sep1($.identifier, "::"))), $._terminator, sep($._statement, $._terminator), "end"),

    module_declaration: $ => seq("module", $.identifier, $._terminator, sep($._statement, $._terminator), "end"),

    while_statement: $ => seq("while", $.condition, $._statement_block),
    until_statement: $ => seq("until", $.condition, $._statement_block),
    if_statement: $ => seq("if", $.condition, $._then_elsif_else_block),
    unless_statement: $ => seq("unless", $.condition, $._then_else_block),
    for_statement: $ => seq("for", $._lhs, "in", $._expression, $._statement_block),
    begin_statement: $ => seq(
      "begin",
      sep($._statement, $._terminator),
      repeat($.rescue_block),
      optional($.else_block),
      optional($.ensure_block),
      "end"
    ),

    return_statement: $ => seq("return", optional($._expression)),

    if_modifier: $ => seq($._statement, "if", $._expression),
    unless_modifier: $ => seq($._statement, "unless", $._expression),
    while_modifier: $ => seq($._statement, "while", $._expression),
    until_modifier: $ => seq($._statement, "until", $._expression),

    condition: $ => $._expression,

    _statement_block: $ => choice(
      $._do_block,
      seq($._terminator, sep($._statement, $._terminator), "end")
    ),
    _do_block: $ => seq("do", sep($._statement, $._terminator), "end"),

    then_block: $ => seq(choice("then", $._terminator), sep($._statement, $._terminator)),
    else_block: $ => seq("else", sep($._statement, $._terminator)),
    rescue_block: $ => seq("rescue", commaSep($._argument), choice("do", $._terminator), sep($._statement, $._terminator)),
    ensure_block: $ => seq("ensure", sep($._statement, $._terminator)),

    _then_else_block: $ => seq($.then_block, optional($.else_block), "end"),
    _then_elsif_else_block: $ => seq(
      $.then_block,
      repeat(seq(
        "elsif", $.condition,
        $.then_block
      )),
      optional($.else_block),
      "end"
    ),

    _call: $ => choice($._function_call, $._command),

    _call_arguments: $ => choice(
      commaSep1($._argument),
      $._command
    ),

    _command: $ => choice(
      seq("super", $._call_arguments)
    ),
    _function_call: $ => choice("super"),

    _expression: $ => choice(
      $._argument,
      $.yield,
      $.and,
      $.or,
      $.not,
      $.defined,
      $.assignment,
      $.conditional,
      $.range,
      $.boolean_or,
      $.boolean_and,
      $.relational,
      $.comparison,
      $.bitwise_or,
      $.bitwise_and,
      $.shift,
      $.additive,
      $.multiplicative,
      $.unary_minus,
      $.exponential,
      $.complement,
      $._literal
    ),

    _argument: $ => choice($._primary),

    _primary: $ => choice(
      seq("(", sep($._statement, $._terminator), ")"),
      $._lhs
    ),

    scope_resolution_expression: $ => seq(optional($._primary), '::', $.identifier),
    subscript_expression: $ => seq($._primary, "[", commaSep($._argument), "]"),
    member_access: $ => seq($._primary, ".", $.identifier),
    yield: $ => seq("yield", optional($._expression)),

    and: $ => prec.left(PREC.AND, seq($._expression, "and", $._expression)),
    or: $ => prec.left(PREC.OR, seq($._expression, "or", $._expression)),
    not: $ => prec.right(PREC.NOT, seq("not", $._expression)),
    defined: $ => prec(PREC.DEFINED, seq("defined?", $._expression)),
    assignment: $ => prec.right(PREC.ASSIGN, seq($._lhs, '=', $._expression)),
    conditional: $ => prec.right(PREC.CONDITIONAL, seq($._expression, '?', $._expression, ':', $._expression)),
    range: $ => prec.right(PREC.RANGE, seq($._expression, choice('..', '...'), $._expression)),

    boolean_or: $ => prec.left(PREC.BOOLEAN_OR, seq($._expression, '||', $._expression)),
    boolean_and: $ => prec.left(PREC.BOOLEAN_OR, seq($._expression, '&&', $._expression)),

    relational: $ => prec.right(PREC.RELATIONAL, seq($._expression, choice('==', '!=', '===', '<=>', '=~', '!~'), $._expression)),
    comparison: $ => prec.left(PREC.COMPARISON, seq($._expression, choice('<', '<=', '>', '>='), $._expression)),

    bitwise_or: $ => prec.left(PREC.BITWISE_OR, seq($._expression, choice('^', '|'), $._expression)),
    bitwise_and: $ => prec.left(PREC.BITWISE_AND, seq($._expression, '&', $._expression)),
    shift: $ => prec.left(PREC.SHIFT, seq($._expression, choice('<<', '>>'), $._expression)),

    additive: $ => prec.left(PREC.ADDITIVE, seq($._expression, choice('-', '+'), $._expression)),
    multiplicative: $ => prec.left(PREC.MULTIPLICATIVE, seq($._expression, choice('*', '/', '%'), $._expression)),

    unary_minus: $ => prec.right(PREC.UNARY_MINUS, seq('-', $._expression)),

    exponential: $ => prec.right(PREC.EXPONENTIAL, seq($._expression, '**', $._expression)),

    complement: $ => prec.right(PREC.COMPLEMENT, seq(choice('!', '~', '+'), $._expression)),

    _block_variable: $ => choice($._lhs, $._mlhs),
    _mlhs: $ => choice(
      seq(commaSep1($._mlhs_item), optional(seq("*", optional($._lhs)))),
      seq("*", optional($._lhs))
    ),
    _mlhs_item: $ => choice($._lhs, seq("(", $._mlhs, ")")),
    _lhs: $ => choice(
      $._variable,
      $.scope_resolution_expression,
      $.subscript_expression,
      $.member_access
    ),
    _variable: $ => choice($.identifier , 'self'),

    identifier: $ => token(seq(repeat(choice('@', '$')), identifierPattern)),

    comment: $ => token(choice(
      seq('#', /.*/),
      seq(
        '=begin\n',
        repeat(/.*\n/),
        '=end\n'
      )
    )),

    _literal: $ => choice(
      $.symbol,
      $.integer,
      $.float,
      $.boolean,
      $.nil,
      $.string,
      $.subshell,
      $.array,
      $.regex
    ),

    symbol: $ => choice(
      token(seq(':', choice(identifierPattern, choice.apply(null, operators)))),
      seq(":'", $._single_quoted_continuation),
      seq(':"', $._double_quoted_continuation),
      choice.apply(null, unbalancedDelimiters.split('').map(d => stringBody('%s' + d, d))),
      seq(/%s/, $._uninterpolated_angle),
      seq(/%s/, $._uninterpolated_bracket),
      seq(/%s/, $._uninterpolated_paren),
      seq(/%s/, $._uninterpolated_brace)
    ),

    integer: $ => (/0b[01](_?[01])*|0[oO]?[0-7](_?[0-7])*|(0d)?\d(_?\d)*|0x[0-9a-fA-F](_?[0-9a-fA-F])*/),
    float: $ => (/\d(_?\d)*\.\d(_?\d)*([eE]\d(_?\d)*)?/),
    boolean: $ => choice('true', 'false', 'TRUE', 'FALSE'),
    nil: $ => choice('nil', 'NIL'),

    string: $ => choice(
      seq("'", $._single_quoted_continuation),
      seq('"', $._double_quoted_continuation),
      choice.apply(null, unbalancedDelimiters.split('').map(d => stringBody(RegExp('%(Q|)\\' + d), d, $.interpolation))),
      seq(/%Q?/, $._interpolated_angle),
      seq(/%Q?/, $._interpolated_bracket),
      seq(/%Q?/, $._interpolated_paren),
      seq(/%Q?/, $._interpolated_brace),
      choice.apply(null, unbalancedDelimiters.split('').map(d => stringBody('%q' + d, d))),
      seq('%q', $._uninterpolated_angle),
      seq('%q', $._uninterpolated_bracket),
      seq('%q', $._uninterpolated_paren),
      seq('%q', $._uninterpolated_brace)
    ),
    _single_quoted_continuation: $ => stringBody(blank(), "'"),
    _double_quoted_continuation: $ => stringBody(blank(), '"', $.interpolation),

    _interpolated_angle: $ => balancedStringBody($._interpolated_angle, '<', '>', $.interpolation),
    _interpolated_bracket: $ => balancedStringBody($._interpolated_bracket, '[', ']', $.interpolation),
    _interpolated_paren: $ => balancedStringBody($._interpolated_paren, '(', ')', $.interpolation),
    _interpolated_brace: $ => balancedStringBody($._interpolated_brace, '{', '}', $.interpolation),
    _uninterpolated_angle: $ => balancedStringBody($._uninterpolated_angle, '<', '>'),
    _uninterpolated_bracket: $ => balancedStringBody($._uninterpolated_bracket, '[', ']'),
    _uninterpolated_paren: $ => balancedStringBody($._uninterpolated_paren, '(', ')'),
    _uninterpolated_brace: $ => balancedStringBody($._uninterpolated_brace, '{', '}'),
    interpolation: $ => seq(token(prec(PREC.LITERAL, '#{')), $._expression, '}'),

    subshell: $ => choice(
      stringBody('`', '`'),
      choice.apply(null, unbalancedDelimiters.split('').map(d => stringBody('%x' + d, d, $.interpolation))),
      seq('%x', $._interpolated_angle),
      seq('%x', $._interpolated_bracket),
      seq('%x', $._interpolated_paren),
      seq('%x', $._interpolated_brace)
    ),

    array: $ => choice(
      seq('[', $._array_items, ']'),
      choice.apply(null, unbalancedDelimiters.split('').map(d => stringBody(RegExp('%[wi]\\' + d), d))),
      seq(/%[wi]/, $._uninterpolated_angle),
      seq(/%[wi]/, $._uninterpolated_bracket),
      seq(/%[wi]/, $._uninterpolated_paren),
      seq(/%[wi]/, $._uninterpolated_brace),
      choice.apply(null, unbalancedDelimiters.split('').map(d => stringBody(RegExp('%[WI]\\' + d), d, $.interpolation))),
      seq(/%[WI]/, $._interpolated_angle),
      seq(/%[WI]/, $._interpolated_bracket),
      seq(/%[WI]/, $._interpolated_paren),
      seq(/%[WI]/, $._interpolated_brace)
    ),
    _array_items: $ => optional(seq($._expression, optional(seq(',', $._array_items)))),

    regex: $ => prec(PREC.LITERAL, choice(
      regexBody('/', '/', $.interpolation),
      choice.apply(null, unbalancedDelimiters.split('').map(d => regexBody('%r' + d, d, $.interpolation))),
      seq('%r', $._regex_interpolated_angle),
      seq('%r', $._regex_interpolated_bracket),
      seq('%r', $._regex_interpolated_paren),
      seq('%r', $._regex_interpolated_brace)
    )),
    _regex_interpolated_angle: $ => regexBody('<', '>', $.interpolation, $._regex_interpolated_angle),
    _regex_interpolated_bracket: $ => regexBody('[', ']', $.interpolation, $._regex_interpolated_bracket),
    _regex_interpolated_paren: $ => regexBody('(', ')', $.interpolation, $._regex_interpolated_paren),
    _regex_interpolated_brace: $ => regexBody('{', '}', $.interpolation, $._regex_interpolated_brace),

    _function_name: $ => choice($.identifier, choice.apply(null, operators)),

    _line_break: $ => '\n',
    _terminator: $ => choice($._line_break, ';'),
  }
});

/// Describes the body of a string literal bounded by `open` and `close`, and optionally containing (potentially recursive) references to `insert`.
function stringBody (open, close, insert) {
  var contents = [ /\\./, RegExp('[^\\\\\\' + close + ']') ];
  if (typeof insert !== 'undefined') contents.push(insert);
  return seq(open, repeat(choice.apply(null, contents)), token(prec(PREC.LITERAL, close)));
}

function balancedStringBody (me, open, close, insert) {
  var contents = [ /\\./, me, RegExp('[^\\\\\\' + open + '\\' + close + ']') ];
  if (typeof insert !== 'undefined') contents.push(insert);
  return seq(open, repeat(choice.apply(null, contents)), close);
}

function regexBody (open, close, interpolation, me) {
  var contents = [
    RegExp('\\[[^\\]\\n]*\\]|\\\\.|[^\\' + close + '\\\\\\[\\n]'),
    interpolation
  ];
  if (typeof me !== 'undefined') contents.push(me);
  return seq(open, repeat(choice.apply(null, contents)), token(prec(PREC.LITERAL, RegExp('\\' + close + '[a-z]*'))));
}

function sep1 (rule, separator) {
  return seq(rule, repeat(seq(separator, rule)));
}

function sep (rule, separator) {
  return optional(sep1(rule, separator));
}

function commaSep1 (rule) {
  return sep1(rule, ',')
}

function commaSep (rule) {
  return optional(commaSep1(rule));
}
<|endoftext|>