<commit_before>/**
 * @fileoverview Enforce standardized indentation style
 * @author Raghav Dua <duaraghav8@gmail.com>
 */

'use strict';

function getIndentString (indentStyle, level) {
	return Array (level + 1).join (indentStyle);
}

module.exports = {

	meta: {

		docs: {
			recommended: true,
			type: 'warning',
			description: 'Ensure consistent indentation of 4 spaces per level'
		},

		schema: [{
			oneOf: [
				{ type: 'string', enum: ['tab'] },
				{ type: 'integer', minimum: 0 }
			]
		}]

	},

	create: function (context) {

		// default configurations
		var BASE_INDENTATION_STYLE = ' '.repeat (4),
			BASE_INDENTATION_STYLE_DESC = '4 SPACES';

		if (context.options) {
			if (context.options [0] === 'tab') {
				BASE_INDENTATION_STYLE = '\t';
				BASE_INDENTATION_STYLE_DESC = '1 TAB';
			} else {
				var spCount = context.options [0];

				BASE_INDENTATION_STYLE = ' '.repeat (spCount);
				BASE_INDENTATION_STYLE_DESC = spCount + ' SPACE' + (spCount === 1 ? '' : 'S'); // grammar-nazi-proof error messages
			}
		}

		var BASE_INDENTATION_STYLE_REGEXP_GLOBAL = new RegExp (BASE_INDENTATION_STYLE, 'g');

		var sourceCode = context.getSourceCode ();
		var topLevelDeclarations = ['ContractStatement', 'LibraryStatement'];

		//Ensure NO indentation exists before top-level declarations (contract, library)
		function inspectProgram (emitted) {
			var node = emitted.node;

			if (emitted.exit) {
				return;
			}

			function inspectProgramChild (programChild) {
				//if node's code starts at index 0, getPrevChar() returns null (meaning no errors), so change it to '\n'
				var prevChar = sourceCode.getPrevChar (programChild) || '\n',
					childEndingLine = sourceCode.getEndingLine (programChild),
					childEndingLineText = sourceCode.getTextOnLine (childEndingLine);

				function report (messageText) {
					context.report ({
						node: programChild,
						message: (
							programChild.type.replace ('Statement', '').toLowerCase () +
							( programChild.name ? (' \'' + programChild.name + '\'') : ' statement' ) +
							': ' + messageText
						)
					});
				}

				if (prevChar !== '\n') {
					//either indentation exists, or some other character - both are not allowed
					if (/\s/.test (prevChar)) {
						report ('There should be no indentation before top-level declaration.');
					} else {
						report ('There should be no character(s) before top-level declaration.');
					}
				}

				//if node starts and ends on different lines and its last line starts with a whitespace or multiline/natspec comment, report
				if (
					sourceCode.getLine (programChild) !== childEndingLine &&
					/^(\s+)|(\/\*[^*\/]*\*\/)/.test (childEndingLineText)
				) {
					context.report ({
						node: programChild,
						location: {
							line: childEndingLine,
							column: 0
						},
						message: 'Indentation: Line should not have any indentation or comments at the beginning.'
					});
				}

			}

			node.body.forEach (inspectProgramChild);
		}

		//Ensure level 1 indentation before all immediate children of top-level declarations
		function inspectTopLevelDeclaration (emitted) {
			var body = emitted.node.body || [],
				levelOneIndentRegExp = new RegExp ('^\\n' + BASE_INDENTATION_STYLE + '$'),
				endingLineRegExp = new RegExp ('^' + BASE_INDENTATION_STYLE + '(\\S| *)$');	//either a non-whitespace character or 1 extra whitespace followed by * (closing of multi-line comment)

			if (emitted.exit) {
				return;
			}

			function inspectChild (child) {
				var prevChars = sourceCode.getPrevChars (child, BASE_INDENTATION_STYLE.length+1),
					endingLineNum = sourceCode.getEndingLine (child);

				//if the start of node doesn't follow correct indentation
				if (!levelOneIndentRegExp.test (prevChars)) {
					context.report ({
						node: child,
						message: 'Incorrect indentation: Make sure you use ' + BASE_INDENTATION_STYLE_DESC + ' per level and don\'t precede the code by any comments.'
					});
				}

				//if the node doesn't end on the same line as it starts and the ending line doesn't follow correct indentation
				if (
					sourceCode.getLine (child) !== endingLineNum &&
					!endingLineRegExp.test (sourceCode.getTextOnLine (endingLineNum).slice (0, 5))
				) {
					context.report ({
						node: child,
						location: {
							line: endingLineNum,
							column: 0
						},
						message: 'Incorrect indentation: Make sure you use ' + BASE_INDENTATION_STYLE_DESC + ' per level and don\'t precede the code by any comments.'
					});
				}
			}

			body.forEach (inspectChild);
		}

		//Ensure 1 extra indentation inside Block than before it
		function inspectBlockStatement (emitted) {
			var node = emitted.node;

			//if the complete block resides on the same line, no need to check for indentation
			if (emitted.exit || (sourceCode.getLine (node) === sourceCode.getEndingLine (node))) {
				return;
			}

			var parent = sourceCode.getParent (node),
				parentDeclarationLine = sourceCode.getLine (parent),
				parentDeclarationLineText = sourceCode.getTextOnLine (parentDeclarationLine),
				currentIndent, currentIndentLevel, blockIndent;

			function inspectBlockItem (blockIndent, blockItem) {
				var prevChars = sourceCode.getPrevChars (blockItem, blockIndent.length+1),
					endingLineNum = sourceCode.getEndingLine (blockItem),
					endingLineRegExp = new RegExp ('^' + blockIndent + '\\S.*$');

				if (prevChars !== ('\n' + blockIndent)) {
					context.report ({
						node: blockItem,
						message: 'Incorrect Indentation: make sure only \"' + blockIndent + '\" is used as indentation for this line.'
					});
				}

				/**
				 * If the block item spans over multiple lines, make sure the ending line also follows the indent rule
				 * An exception to this is the if-else statements when they don't have BlockStatement as their body
				 * eg-
				 * if (a)
				 *     foo();
				 * else
				 *     bar();
				 */
				if (
					blockItem.type !== 'IfStatement' &&
					sourceCode.getLine (blockItem) !== endingLineNum &&
					!endingLineRegExp.test (sourceCode.getTextOnLine (endingLineNum))
				) {
					context.report ({
						node: blockItem,
						location: {
							line: endingLineNum,
							column: 0
						},
						message: 'Incorrect Indentation: make sure only \"' + blockIndent + '\" is used as indentation for this line.'
					});
				}
			}

			currentIndent = parentDeclarationLineText.slice (
				0,
				parentDeclarationLineText.indexOf (parentDeclarationLineText.trim ())
			);

			//in case of no match, match() returns null. Return [] instead to avoid crash
			currentIndentLevel = (currentIndent.match (BASE_INDENTATION_STYLE_REGEXP_GLOBAL) || []).length;

			//ensure that there is only whitespace of correct level before the block's parent's code
			if (getIndentString (BASE_INDENTATION_STYLE, currentIndentLevel) !== currentIndent) {
				return;	//exit now, we can' proceed further unless this is fixed
			}

			//indentation of items inside block should be 1 level greater than that of parent
			blockIndent = getIndentString (BASE_INDENTATION_STYLE, currentIndentLevel + 1);
			node.body.forEach (inspectBlockItem.bind (null, blockIndent));
		}

		function inspectStructDeclaration (emitted) {
			var node = emitted.node,
				body = node.body || [],
				endingLineNum = sourceCode.getEndingLine (node);
			var structDeclarationLineText, currentIndent, currentIndentLevel, structIndent;

			function inspectStructAttr (structIndent, attr) {
				var indentRegExp = new RegExp ('^' + structIndent + '[^\\s(\/\*)]'),
					attrLineText = sourceCode.getTextOnLine (sourceCode.getLine (attr));

				//attribute declaration must be preceded by only correct level of indentation & no comments
				!indentRegExp.test (attrLineText) && context.report ({
					node: attr,
					message: 'Incorrect Indentation: Make sure you use exacly \"' + structIndent + '\" for indentation on this line and don\'t precede the declaration by comment(s).'
				});
			}

			if (emitted.exit) {
				return;
			}

			//raise an error and stop linting if more than 3 attributes exist & declaration is on single line
			if (sourceCode.getLine (node) === endingLineNum) {
				return;
			}

			structDeclarationLineText = sourceCode.getTextOnLine (sourceCode.getLine (node));

			currentIndent = structDeclarationLineText.slice (
				0,
				structDeclarationLineText.indexOf (structDeclarationLineText.trim ())
			);

			currentIndentLevel = (currentIndent.match (BASE_INDENTATION_STYLE_REGEXP_GLOBAL) || []).length;

			//ensure that there is only whitespace of correct level on the line containing struct declaration
			if (getIndentString (BASE_INDENTATION_STYLE, currentIndentLevel) !== currentIndent) {
				return;	//exit now, we can' proceed further unless this is fixed
			}

			structIndent = getIndentString (BASE_INDENTATION_STYLE, currentIndentLevel + 1);
			body.forEach (inspectStructAttr.bind (null, structIndent));

		}

		function inspectArrayExpression (emitted) {
			var node = emitted.node, elements = node.elements;
			var endingLineNum = sourceCode.getEndingLine (node),
				arrayExpressionLineText, currentIndent, currentIndentLevel, arrayIndent;

			function inspectElement (arrayIndent, elem) {
				var indentRegExp = new RegExp ('^' + arrayIndent + '[^\\s(\/\*)]'),
					elemLineText = sourceCode.getTextOnLine (sourceCode.getLine (elem));

				//element declaration must be preceded by only correct level of indentation & no comments
				!indentRegExp.test (elemLineText) && context.report ({
					node: elem,
					message: 'Incorrect Indentation: Make sure you use exacly \"' + arrayIndent + '\" for indentation on this line and don\'t precede the declaration by comment(s).'
				});
			}

			if (emitted.exit) {
				return;
			}

			if (sourceCode.getLine (node) === endingLineNum) {
				return;
			}

			arrayExpressionLineText = sourceCode.getTextOnLine (sourceCode.getLine (node));

			currentIndent = arrayExpressionLineText.slice (
				0,
				arrayExpressionLineText.indexOf (arrayExpressionLineText.trim ())
			);

			currentIndentLevel = (currentIndent.match (BASE_INDENTATION_STYLE_REGEXP_GLOBAL) || []).length;

			//ensure that there is only whitespace of correct level on the line containing array expression
			if (getIndentString (BASE_INDENTATION_STYLE, currentIndentLevel) !== currentIndent) {
				return;	//exit now, we can' proceed further unless this is fixed
			}

			arrayIndent = getIndentString (BASE_INDENTATION_STYLE, currentIndentLevel + 1);
			elements.forEach (inspectElement.bind (null, arrayIndent));
		}

		//function params (if on multiple lines)
		function inspectFunctionDeclaration (emitted) {
			var node = emitted.node, params = node.params || [];

			var startLine = sourceCode.getLine (node),
				lastArgLine = params.length ? sourceCode.getEndingLine (params.slice (-1) [0]) : startLine,
				functionDeclarationLineText, currentIndent, currentIndentLevel, paramIndent;

			function inspectParam (paramIndent, param) {
				var indentRegExp = new RegExp ('^' + paramIndent + '[^\\s(\/\*)]'),
					paramLineText = sourceCode.getTextOnLine (sourceCode.getLine (param));

				//parameter declaration must be preceded by only correct level of indentation & no comments
				!indentRegExp.test (paramLineText) && context.report ({
					node: param,
					message: 'Incorrect Indentation: Make sure you use exacly \"' + paramIndent + '\" for indentation on this line and don\'t precede the declaration by comment(s).'
				});
			}

			if (emitted.exit) {
				return;
			}

			if (startLine === lastArgLine) {
				return;
			}

			functionDeclarationLineText = sourceCode.getTextOnLine (startLine);

			currentIndent = functionDeclarationLineText.slice (
				0,
				functionDeclarationLineText.indexOf (functionDeclarationLineText.trim ())
			);

			currentIndentLevel = (currentIndent.match (BASE_INDENTATION_STYLE_REGEXP_GLOBAL) || []).length;

			//ensure that there is only whitespace of correct level on the line containing parameter
			if (getIndentString (BASE_INDENTATION_STYLE, currentIndentLevel) !== currentIndent) {
				return;	//exit now, we can' proceed further unless this is fixed
			}

			paramIndent = getIndentString (BASE_INDENTATION_STYLE, currentIndentLevel + 1);

			params.forEach (inspectParam.bind (null, paramIndent));
		}

		function inspectCallExpression (emitted) {

			var node = emitted.node;
			var endingLineNum = sourceCode.getEndingLine (node),
				callExpressionLineText, currentIndent, currentIndentLevel, argIndent;

			function inspectArgument (argIndent, argument) {
				var indentRegExp = new RegExp ('^' + argIndent + '[^\\s(\/\*)]'),
					argLineText = sourceCode.getTextOnLine (sourceCode.getLine (argument));

				//parameter declaration must be preceded by only correct level of indentation & no comments
				!indentRegExp.test (argLineText) && context.report ({
					node: argument,
					message: 'Incorrect Indentation: Make sure you use exacly \"' + argIndent + '\" for indentation on this line and don\'t precede the declaration by comment(s).'
				});
			}

			if (emitted.exit) {
				return;
			}

			if (sourceCode.getLine (node) === endingLineNum) {
				return;
			}

			callExpressionLineText = sourceCode.getTextOnLine (sourceCode.getLine (node));

			currentIndent = callExpressionLineText.slice (
				0,
				callExpressionLineText.indexOf (callExpressionLineText.trim ())
			);

			currentIndentLevel = (currentIndent.match (BASE_INDENTATION_STYLE_REGEXP_GLOBAL) || []).length;

			//ensure that there is only whitespace of correct level on the line containing parameter
			if (getIndentString (BASE_INDENTATION_STYLE, currentIndentLevel) !== currentIndent) {
				return;	//exit now, we can' proceed further unless this is fixed
			}

			argIndent = getIndentString (BASE_INDENTATION_STYLE, currentIndentLevel + 1);

			node.arguments.forEach (inspectArgument.bind (null, argIndent));

		}

		var response = {
			CallExpression: inspectCallExpression,
			FunctionDeclaration: inspectFunctionDeclaration,
			ArrayExpression: inspectArrayExpression,
			StructDeclaration: inspectStructDeclaration,
			BlockStatement: inspectBlockStatement,
			Program: inspectProgram
		};

		topLevelDeclarations.forEach (function (nodeName) {
			response [nodeName] = inspectTopLevelDeclaration;
		});

		return response;

	}

};
<commit_msg>Update comments in indentation rule<commit_after>/**
 * @fileoverview Enforce standardized indentation style
 * @author Raghav Dua <duaraghav8@gmail.com>
 */

'use strict';

function getIndentString (indentStyle, level) {
	return Array (level + 1).join (indentStyle);
}

module.exports = {

	meta: {

		docs: {
			recommended: true,
			type: 'warning',
			description: 'Ensure consistent indentation of 4 spaces per level'
		},

		schema: [{
			oneOf: [
				{ type: 'string', enum: ['tab'] },
				{ type: 'integer', minimum: 0 }
			]
		}]

	},

	create: function (context) {

		// default configurations
		var BASE_INDENTATION_STYLE = ' '.repeat (4),
			BASE_INDENTATION_STYLE_DESC = '4 SPACES';

		if (context.options) {
			if (context.options [0] === 'tab') {
				BASE_INDENTATION_STYLE = '\t';
				BASE_INDENTATION_STYLE_DESC = '1 TAB';
			} else {
				var spCount = context.options [0];

				BASE_INDENTATION_STYLE = ' '.repeat (spCount);
				BASE_INDENTATION_STYLE_DESC = spCount + ' SPACE' + (spCount === 1 ? '' : 'S'); // grammar-nazi-proof error messages
			}
		}

		var BASE_INDENTATION_STYLE_REGEXP_GLOBAL = new RegExp (BASE_INDENTATION_STYLE, 'g');

		var sourceCode = context.getSourceCode ();
		var topLevelDeclarations = ['ContractStatement', 'LibraryStatement'];

		//Ensure NO indentation exists before top-level declarations (contract, library)
		function inspectProgram (emitted) {
			var node = emitted.node;

			if (emitted.exit) {
				return;
			}

			function inspectProgramChild (programChild) {
				//if node's code starts at index 0, getPrevChar() returns null (meaning no errors), so change it to '\n'
				var prevChar = sourceCode.getPrevChar (programChild) || '\n',
					childEndingLine = sourceCode.getEndingLine (programChild),
					childEndingLineText = sourceCode.getTextOnLine (childEndingLine);

				function report (messageText) {
					context.report ({
						node: programChild,
						message: (
							programChild.type.replace ('Statement', '').toLowerCase () +
							( programChild.name ? (' \'' + programChild.name + '\'') : ' statement' ) +
							': ' + messageText
						)
					});
				}

				if (prevChar !== '\n') {
					//either indentation exists, or some other character - both are not allowed
					if (/\s/.test (prevChar)) {
						report ('There should be no indentation before top-level declaration.');
					} else {
						report ('There should be no character(s) before top-level declaration.');
					}
				}

				//if node starts and ends on different lines and its last line starts with a whitespace or multiline/natspec comment, report
				if (
					sourceCode.getLine (programChild) !== childEndingLine &&
					/^(\s+)|(\/\*[^*\/]*\*\/)/.test (childEndingLineText)
				) {
					context.report ({
						node: programChild,
						location: {
							line: childEndingLine,
							column: 0
						},
						message: 'Indentation: Line should not have any indentation or comments at the beginning.'
					});
				}

			}

			node.body.forEach (inspectProgramChild);
		}

		//Ensure level 1 indentation before all immediate children of top-level declarations
		function inspectTopLevelDeclaration (emitted) {
			var body = emitted.node.body || [],
				levelOneIndentRegExp = new RegExp ('^\\n' + BASE_INDENTATION_STYLE + '$'),
				endingLineRegExp = new RegExp ('^' + BASE_INDENTATION_STYLE + '(\\S| *)$');	//either a non-whitespace character or 1 extra whitespace followed by * (closing of multi-line comment)

			if (emitted.exit) {
				return;
			}

			function inspectChild (child) {
				var prevChars = sourceCode.getPrevChars (child, BASE_INDENTATION_STYLE.length+1),
					endingLineNum = sourceCode.getEndingLine (child);

				//if the start of node doesn't follow correct indentation
				if (!levelOneIndentRegExp.test (prevChars)) {
					context.report ({
						node: child,
						message: 'Incorrect indentation: Make sure you use ' + BASE_INDENTATION_STYLE_DESC + ' per level and don\'t precede the code by any comments.'
					});
				}

				//if the node doesn't end on the same line as it starts and the ending line doesn't follow correct indentation
				if (
					sourceCode.getLine (child) !== endingLineNum &&
					!endingLineRegExp.test (sourceCode.getTextOnLine (endingLineNum).slice (0, 5))
				) {
					context.report ({
						node: child,
						location: {
							line: endingLineNum,
							column: 0
						},
						message: 'Incorrect indentation: Make sure you use ' + BASE_INDENTATION_STYLE_DESC + ' per level and don\'t precede the code by any comments.'
					});
				}
			}

			body.forEach (inspectChild);
		}

		//Ensure 1 extra indentation inside Block than before it
		function inspectBlockStatement (emitted) {
			var node = emitted.node;

			//if the complete block resides on the same line, no need to check for indentation
			if (emitted.exit || (sourceCode.getLine (node) === sourceCode.getEndingLine (node))) {
				return;
			}

			var parent = sourceCode.getParent (node),
				parentDeclarationLine = sourceCode.getLine (parent),
				parentDeclarationLineText = sourceCode.getTextOnLine (parentDeclarationLine),
				currentIndent, currentIndentLevel, blockIndent;

			function inspectBlockItem (blockIndent, blockItem) {
				var prevChars = sourceCode.getPrevChars (blockItem, blockIndent.length+1),
					endingLineNum = sourceCode.getEndingLine (blockItem),
					endingLineRegExp = new RegExp ('^' + blockIndent + '\\S.*$');

				if (prevChars !== ('\n' + blockIndent)) {
					context.report ({
						node: blockItem,
						message: 'Incorrect Indentation: make sure only \"' + blockIndent + '\" is used as indentation for this line.'
					});
				}

				/**
				 * If the block item spans over multiple lines, make sure the ending line also follows the indent rule
				 * An exception to this is the if-else statements when they don't have BlockStatement as their body
				 * eg-
				 * if (a)
				 *     foo();
				 * else
				 *     bar();
				 */
				if (
					blockItem.type !== 'IfStatement' &&
					sourceCode.getLine (blockItem) !== endingLineNum &&
					!endingLineRegExp.test (sourceCode.getTextOnLine (endingLineNum))
				) {
					context.report ({
						node: blockItem,
						location: {
							line: endingLineNum,
							column: 0
						},
						message: 'Incorrect Indentation: make sure only \"' + blockIndent + '\" is used as indentation for this line.'
					});
				}
			}

			currentIndent = parentDeclarationLineText.slice (
				0,
				parentDeclarationLineText.indexOf (parentDeclarationLineText.trim ())
			);

			//in case of no match, match() returns null. Return [] instead to avoid crash
			currentIndentLevel = (currentIndent.match (BASE_INDENTATION_STYLE_REGEXP_GLOBAL) || []).length;

			//ensure that there is only whitespace of correct level before the block's parent's code
			if (getIndentString (BASE_INDENTATION_STYLE, currentIndentLevel) !== currentIndent) {
				return;	//exit now, we can' proceed further unless this is fixed
			}

			//indentation of items inside block should be 1 level greater than that of parent
			blockIndent = getIndentString (BASE_INDENTATION_STYLE, currentIndentLevel + 1);
			node.body.forEach (inspectBlockItem.bind (null, blockIndent));
		}

		function inspectStructDeclaration (emitted) {
			var node = emitted.node,
				body = node.body || [],
				endingLineNum = sourceCode.getEndingLine (node);
			var structDeclarationLineText, currentIndent, currentIndentLevel, structIndent;

			function inspectStructAttr (structIndent, attr) {
				var indentRegExp = new RegExp ('^' + structIndent + '[^\\s(\/\*)]'),
					attrLineText = sourceCode.getTextOnLine (sourceCode.getLine (attr));

				//attribute declaration must be preceded by only correct level of indentation & no comments
				!indentRegExp.test (attrLineText) && context.report ({
					node: attr,
					message: 'Incorrect Indentation: Make sure you use exacly \"' + structIndent + '\" for indentation on this line and don\'t precede the declaration by comment(s).'
				});
			}

			if (emitted.exit) {
				return;
			}

			// No need to lint further if entire struct declaration is on single line
			if (sourceCode.getLine (node) === endingLineNum) {
				return;
			}

			structDeclarationLineText = sourceCode.getTextOnLine (sourceCode.getLine (node));

			currentIndent = structDeclarationLineText.slice (
				0,
				structDeclarationLineText.indexOf (structDeclarationLineText.trim ())
			);

			currentIndentLevel = (currentIndent.match (BASE_INDENTATION_STYLE_REGEXP_GLOBAL) || []).length;

			//ensure that there is only whitespace of correct level on the line containing struct declaration
			if (getIndentString (BASE_INDENTATION_STYLE, currentIndentLevel) !== currentIndent) {
				return;	//exit now, we can' proceed further unless this is fixed
			}

			structIndent = getIndentString (BASE_INDENTATION_STYLE, currentIndentLevel + 1);
			body.forEach (inspectStructAttr.bind (null, structIndent));

		}

		function inspectArrayExpression (emitted) {
			var node = emitted.node, elements = node.elements;
			var endingLineNum = sourceCode.getEndingLine (node),
				arrayExpressionLineText, currentIndent, currentIndentLevel, arrayIndent;

			function inspectElement (arrayIndent, elem) {
				var indentRegExp = new RegExp ('^' + arrayIndent + '[^\\s(\/\*)]'),
					elemLineText = sourceCode.getTextOnLine (sourceCode.getLine (elem));

				//element declaration must be preceded by only correct level of indentation & no comments
				!indentRegExp.test (elemLineText) && context.report ({
					node: elem,
					message: 'Incorrect Indentation: Make sure you use exacly \"' + arrayIndent + '\" for indentation on this line and don\'t precede the declaration by comment(s).'
				});
			}

			if (emitted.exit) {
				return;
			}

			// No need to lint further if entire arary declaration is on single line
			if (sourceCode.getLine (node) === endingLineNum) {
				return;
			}

			arrayExpressionLineText = sourceCode.getTextOnLine (sourceCode.getLine (node));

			currentIndent = arrayExpressionLineText.slice (
				0,
				arrayExpressionLineText.indexOf (arrayExpressionLineText.trim ())
			);

			currentIndentLevel = (currentIndent.match (BASE_INDENTATION_STYLE_REGEXP_GLOBAL) || []).length;

			//ensure that there is only whitespace of correct level on the line containing array expression
			if (getIndentString (BASE_INDENTATION_STYLE, currentIndentLevel) !== currentIndent) {
				return;	//exit now, we can' proceed further unless this is fixed
			}

			arrayIndent = getIndentString (BASE_INDENTATION_STYLE, currentIndentLevel + 1);
			elements.forEach (inspectElement.bind (null, arrayIndent));
		}

		//function params (if on multiple lines)
		function inspectFunctionDeclaration (emitted) {
			var node = emitted.node, params = node.params || [];

			var startLine = sourceCode.getLine (node),
				lastArgLine = params.length ? sourceCode.getEndingLine (params.slice (-1) [0]) : startLine,
				functionDeclarationLineText, currentIndent, currentIndentLevel, paramIndent;

			function inspectParam (paramIndent, param) {
				var indentRegExp = new RegExp ('^' + paramIndent + '[^\\s(\/\*)]'),
					paramLineText = sourceCode.getTextOnLine (sourceCode.getLine (param));

				//parameter declaration must be preceded by only correct level of indentation & no comments
				!indentRegExp.test (paramLineText) && context.report ({
					node: param,
					message: 'Incorrect Indentation: Make sure you use exacly \"' + paramIndent + '\" for indentation on this line and don\'t precede the declaration by comment(s).'
				});
			}

			if (emitted.exit) {
				return;
			}

			if (startLine === lastArgLine) {
				return;
			}

			functionDeclarationLineText = sourceCode.getTextOnLine (startLine);

			currentIndent = functionDeclarationLineText.slice (
				0,
				functionDeclarationLineText.indexOf (functionDeclarationLineText.trim ())
			);

			currentIndentLevel = (currentIndent.match (BASE_INDENTATION_STYLE_REGEXP_GLOBAL) || []).length;

			//ensure that there is only whitespace of correct level on the line containing parameter
			if (getIndentString (BASE_INDENTATION_STYLE, currentIndentLevel) !== currentIndent) {
				return;	//exit now, we can' proceed further unless this is fixed
			}

			paramIndent = getIndentString (BASE_INDENTATION_STYLE, currentIndentLevel + 1);

			params.forEach (inspectParam.bind (null, paramIndent));
		}

		function inspectCallExpression (emitted) {

			var node = emitted.node;
			var endingLineNum = sourceCode.getEndingLine (node),
				callExpressionLineText, currentIndent, currentIndentLevel, argIndent;

			function inspectArgument (argIndent, argument) {
				var indentRegExp = new RegExp ('^' + argIndent + '[^\\s(\/\*)]'),
					argLineText = sourceCode.getTextOnLine (sourceCode.getLine (argument));

				//parameter declaration must be preceded by only correct level of indentation & no comments
				!indentRegExp.test (argLineText) && context.report ({
					node: argument,
					message: 'Incorrect Indentation: Make sure you use exacly \"' + argIndent + '\" for indentation on this line and don\'t precede the declaration by comment(s).'
				});
			}

			if (emitted.exit) {
				return;
			}

			if (sourceCode.getLine (node) === endingLineNum) {
				return;
			}

			callExpressionLineText = sourceCode.getTextOnLine (sourceCode.getLine (node));

			currentIndent = callExpressionLineText.slice (
				0,
				callExpressionLineText.indexOf (callExpressionLineText.trim ())
			);

			currentIndentLevel = (currentIndent.match (BASE_INDENTATION_STYLE_REGEXP_GLOBAL) || []).length;

			//ensure that there is only whitespace of correct level on the line containing parameter
			if (getIndentString (BASE_INDENTATION_STYLE, currentIndentLevel) !== currentIndent) {
				return;	//exit now, we can' proceed further unless this is fixed
			}

			argIndent = getIndentString (BASE_INDENTATION_STYLE, currentIndentLevel + 1);

			node.arguments.forEach (inspectArgument.bind (null, argIndent));

		}

		var response = {
			CallExpression: inspectCallExpression,
			FunctionDeclaration: inspectFunctionDeclaration,
			ArrayExpression: inspectArrayExpression,
			StructDeclaration: inspectStructDeclaration,
			BlockStatement: inspectBlockStatement,
			Program: inspectProgram
		};

		topLevelDeclarations.forEach (function (nodeName) {
			response [nodeName] = inspectTopLevelDeclaration;
		});

		return response;

	}

};
<|endoftext|>


<commit_before>'use strict';

/*!
 * node-bb10
 * Copyright(c) 2013 Endare bvba <info@endare.com>
 * MIT Licensed
 *
 *
 * This class forms the message that will be send to the Push Protocol Gateway. The message is uniquely
 * identified.
 *
 * @author Sam Verschueren        <sam.verschueren@gmail.com>
 * @since 18 apr. 2013
 */

var constants = require('./Constants');

/**
 * Creates a new message that can be pushed to the Push Protocol Gateway. The PushMessage has a unique identifier
 * to identify the message in the outside world. This identifier must be globaly unique. Therefore, the id is mostly
 * constructed out of the company's url in combination with the name of the application and the timestamp. An example of
 * the id could be com.company.myapp13254655416 where myapp is the name of the application.
 *
 * @param {String} id       An identifier that should be unique around the world. Mostly a combination of the company's url and the timestamp.
 * @param {String} message  The message that should be send to the Push Protocol Gateway.
 */
function PushMessage(id, message) {
    this.id = id;
    this.setMessage(message);
    this.setDeliveryMethod('notspecified');

    this.recipients = [];
}

/**
 * Sets the message that needs to be pushed to the device.
 *
 * @param {String} message The message that should be send to the Push Protocol Gateway.
 */
PushMessage.prototype.setMessage = function(message) {
    this.message = message;
};

/**
 * The delivery-method attribute is used to specify the over the air delivery desired by the Push Initiator.
 * Valid values are "confirmed", "preferconfirmed", "unconfirmed" and "notspecified". The
 * value "unconfirmed" means that the message MUST be delivered in an unconfirmed manner. Note that a
 * Push Initiator may request client confirmation without requesting ppg-notify-requested-to - the result
 * is that the message is confirmed over the air but the PPG does not inform the Push Initiator. The value
 * "preferconfirmed" allows the Push Initiator to inform the PPG of preferences. The PPG SHOULD try to
 * deliver the message as preferred, but may use another method if not able to use the preferred choice. The value
 * "unconfirmed" means that the message MUST be delivered in an unconfirmed manner. The value
 * "notspecified" indicates that the Push Initiator does not care whether the PPG uses confirmed delivery or
 * unconfirmed delivery - the choice is up to the PPG.
 *
 * @param  {String} deliveryMethod  The delivery desired by the Push Initiator.
 * @throws {Error}                  If the delivery method is not valid.
 */
PushMessage.prototype.setDeliveryMethod = function(deliveryMethod) {
    if(constants.DELIVERY_METHODS.indexOf(deliveryMethod) === -1) {
        throw new Error('The delivery method must be one of the following: confirmed | preferconfirmed | unconfirmed | notspecified');
    }

    this.deliveryMethod = deliveryMethod;
};

/**
 * Removes all the recipients from the recipient list.
 */
PushMessage.prototype.clearRecepients = function() {
    this.recipients = [];
};

/**
 * Adds a new recipient to the message.
 *
 * @param {Object} token The unique token of the recipient.
 */
PushMessage.prototype.addRecipient = function(token) {
    this.recipients.push(token);
};

/**
 * Adds multiple recipients at once.
 *
 * @param {Object} tokens An array of unique recipient tokens.
 */
PushMessage.prototype.addAllRecipients = function(tokens) {
    for(var i = 0; i < tokens.length; i++) {
        this.addRecipient(tokens[i]);
    }
};

/**
 * Converts the PushMessage to the correct Push Access Protocol message.
 *
 * @param  {Object} options The attribute options of the push message.
 * @throws {Error}          If the message doesn't have any recipients.
 */
PushMessage.prototype.toPAPMessage = function(options) {
    if(this.recipients.length === 0) {
        throw new Error('Please add some recipients before sending this PushMessage.');
    }

    var body = '';
    body += '--' + constants.BOUNDARY + constants.NEW_LINE;
    body += 'Content-Type: application/xml; charset=UTF-8' + constants.NEW_LINE;
    body += '' + constants.NEW_LINE;
    body += '<?xml version="1.0"?>' + constants.NEW_LINE;
    body += '<!DOCTYPE pap PUBLIC "-//WAPFORUM//DTD PAP 2.1//EN" "http://www.openmobilealliance.org/tech/DTD/pap_2.1.dtd">' + constants.NEW_LINE;
    body += '<pap>' + constants.NEW_LINE;

    var attributes = '';

    for(var key in options) {
        attributes += key + '="' + options[key] + '" ';
    }

    body += '    <push-message ' + attributes + '>' + constants.NEW_LINE;

    for(var i = 0; i < this.recipients.length; i++) {
        body += '        <address address-value="' + this.recipients[i] + '" />' + constants.NEW_LINE;
    }

    body += '        <quality-of-service delivery-method="' + this.deliveryMethod + '" />' + constants.NEW_LINE;
    body += '    </push-message>' + constants.NEW_LINE;
    body += '</pap>' + constants.NEW_LINE;
    body += '--' + constants.BOUNDARY + constants.NEW_LINE;
    body += 'Content-Encoding: binary' + constants.NEW_LINE;
    body += 'Content-Type: text/html' + constants.NEW_LINE;
    body += 'Push-Message-ID: ' + this.id + constants.NEW_LINE;
    body += '' + constants.NEW_LINE;
    body += this.message + constants.NEW_LINE;
    body += '' + constants.NEW_LINE;
    body += '--' + constants.BOUNDARY + '--' + constants.NEW_LINE;
    body += '' + constants.NEW_LINE;

    return body;
};

module.exports = PushMessage;
<commit_msg>PushMessage now throws an error if no ID is specified.<commit_after>'use strict';

/*!
 * node-bb10
 * Copyright(c) 2013 Endare bvba <info@endare.com>
 * MIT Licensed
 *
 *
 * This class forms the message that will be send to the Push Protocol Gateway. The message is uniquely
 * identified.
 *
 * @author Sam Verschueren        <sam.verschueren@gmail.com>
 * @since 18 apr. 2013
 */

var constants = require('./Constants');

/**
 * Creates a new message that can be pushed to the Push Protocol Gateway. The PushMessage has a unique identifier
 * to identify the message in the outside world. This identifier must be globaly unique. Therefore, the id is mostly
 * constructed out of the company's url in combination with the name of the application and the timestamp. An example of
 * the id could be com.company.myapp13254655416 where myapp is the name of the application.
 *
 * @param  {String} id      An identifier that should be unique around the world. Mostly a combination of the company's url and the timestamp.
 * @param  {String} message The message that should be send to the Push Protocol Gateway.
 * @throws {Error}          If no ID is specified.
 */
function PushMessage(id, message) {
    if(id.trim() === '') {
        throw new Error('Please provide a message ID.');
    }

    this.id = id.trim();
    this.setMessage(message);
    this.setDeliveryMethod('notspecified');

    this.recipients = [];
}

/**
 * Sets the message that needs to be pushed to the device.
 *
 * @param {String} message The message that should be send to the Push Protocol Gateway.
 */
PushMessage.prototype.setMessage = function(message) {
    this.message = message;
};

/**
 * The delivery-method attribute is used to specify the over the air delivery desired by the Push Initiator.
 * Valid values are "confirmed", "preferconfirmed", "unconfirmed" and "notspecified". The
 * value "unconfirmed" means that the message MUST be delivered in an unconfirmed manner. Note that a
 * Push Initiator may request client confirmation without requesting ppg-notify-requested-to - the result
 * is that the message is confirmed over the air but the PPG does not inform the Push Initiator. The value
 * "preferconfirmed" allows the Push Initiator to inform the PPG of preferences. The PPG SHOULD try to
 * deliver the message as preferred, but may use another method if not able to use the preferred choice. The value
 * "unconfirmed" means that the message MUST be delivered in an unconfirmed manner. The value
 * "notspecified" indicates that the Push Initiator does not care whether the PPG uses confirmed delivery or
 * unconfirmed delivery - the choice is up to the PPG.
 *
 * @param  {String} deliveryMethod  The delivery desired by the Push Initiator.
 * @throws {Error}                  If the delivery method is not valid.
 */
PushMessage.prototype.setDeliveryMethod = function(deliveryMethod) {
    if(constants.DELIVERY_METHODS.indexOf(deliveryMethod) === -1) {
        throw new Error('The delivery method must be one of the following: ' + constants.DELIVERY_METHODS.join(', '));
    }

    this.deliveryMethod = deliveryMethod;
};

/**
 * Removes all the recipients from the recipient list.
 */
PushMessage.prototype.clearRecepients = function() {
    this.recipients = [];
};

/**
 * Adds a new recipient to the message.
 *
 * @param {Object} token The unique token of the recipient.
 */
PushMessage.prototype.addRecipient = function(token) {
    this.recipients.push(token);
};

/**
 * Adds multiple recipients at once.
 *
 * @param {Object} tokens An array of unique recipient tokens.
 */
PushMessage.prototype.addAllRecipients = function(tokens) {
    for(var i = 0; i < tokens.length; i++) {
        this.addRecipient(tokens[i]);
    }
};

/**
 * Converts the PushMessage to the correct Push Access Protocol message.
 *
 * @param  {Object} options The attribute options of the push message.
 * @throws {Error}          If the message doesn't have any recipients.
 */
PushMessage.prototype.toPAPMessage = function(options) {
    if(this.recipients.length === 0) {
        throw new Error('Please add some recipients before sending this PushMessage.');
    }

    var body = '';
    body += '--' + constants.BOUNDARY + constants.NEW_LINE;
    body += 'Content-Type: application/xml; charset=UTF-8' + constants.NEW_LINE;
    body += '' + constants.NEW_LINE;
    body += '<?xml version="1.0"?>' + constants.NEW_LINE;
    body += '<!DOCTYPE pap PUBLIC "-//WAPFORUM//DTD PAP 2.1//EN" "http://www.openmobilealliance.org/tech/DTD/pap_2.1.dtd">' + constants.NEW_LINE;
    body += '<pap>' + constants.NEW_LINE;

    var attributes = '';

    for(var key in options) {
        attributes += key + '="' + options[key] + '" ';
    }

    body += '    <push-message ' + attributes + '>' + constants.NEW_LINE;

    for(var i = 0; i < this.recipients.length; i++) {
        body += '        <address address-value="' + this.recipients[i] + '" />' + constants.NEW_LINE;
    }

    body += '        <quality-of-service delivery-method="' + this.deliveryMethod + '" />' + constants.NEW_LINE;
    body += '    </push-message>' + constants.NEW_LINE;
    body += '</pap>' + constants.NEW_LINE;
    body += '--' + constants.BOUNDARY + constants.NEW_LINE;
    body += 'Content-Encoding: binary' + constants.NEW_LINE;
    body += 'Content-Type: text/html' + constants.NEW_LINE;
    body += 'Push-Message-ID: ' + this.id + constants.NEW_LINE;
    body += '' + constants.NEW_LINE;
    body += this.message + constants.NEW_LINE;
    body += '' + constants.NEW_LINE;
    body += '--' + constants.BOUNDARY + '--' + constants.NEW_LINE;
    body += '' + constants.NEW_LINE;

    return body;
};

module.exports = PushMessage;
<|endoftext|>


<commit_before>'use strict';

var fs = require('fs');
var sh = require('shelljs');
var ConfigurationManager = require('../src/configuration-manager');

describe('Configuration manager', function() {
  var cManager = new ConfigurationManager();

  describe('methods with config', function() {
    var dirName = 'config/';
    var path = 'config/config.json';

    it('should run isExistOrCreate', function(done) {
      fs.exists(dirName, function (exists) {
        expect(exists).toBeFalsy();
      });
      cManager.configFile.isExistOrCreate = function() {
      };
      cManager.gitignore.update = function() {
      };
      spyOn(cManager.configFile, 'isExistOrCreate').and.callThrough();
      spyOn(cManager.gitignore, 'update').and.callThrough();

      cManager.init();

      expect(cManager.gitignore.update).toHaveBeenCalled();
      expect(cManager.configFile.isExistOrCreate).toHaveBeenCalled();

      fs.exists(path, function (exists) {
        expect(exists).toBeFalsy();
        done();
      });
    });

    it('should getConfig', function() {
      var expected = {
        a: 1,
        b: 2
      };
      cManager.configFile.get = function() {
        return expected;
      }
      spyOn(cManager.configFile, 'get').and.callThrough();

      var obj = cManager.getConfig();

      expect(cManager.configFile.get).toHaveBeenCalled();
      expect(obj).toEqual(expected);
    });

    it('should setConfig', function() {
      var expected = {
        a: 1,
        b: 2
      };
      cManager.configFile.set = function(obj) {
      }
      spyOn(cManager.configFile, 'set').and.callThrough();

      var obj = cManager.setConfig();

      expect(cManager.configFile.set).toHaveBeenCalled();
    });
  });

  describe('methods with version', function() {
    it('should getVersion', function() {
      cManager.version.get = function() {
        var v = '0.0.0';
        return v;
      };
      spyOn(cManager.version, 'get').and.callThrough();
      var expected = '0.0.0'

      var version = cManager.getVersion();

      expect(cManager.version.get).toHaveBeenCalled();
      expect(version).toEqual(expected);
    });

    it('should setVersion', function() {
      var version;
      cManager.version.set = function(newVersion) {
        version = newVersion;
      };
      spyOn(cManager.version, 'set').and.callThrough();
      var expected = '0.0.1'
      var value = '0.0.1';

      cManager.setVersion(value);

      expect(cManager.version.set).toHaveBeenCalled();
      expect(version).toEqual(expected);
    });

    it('should incVersion', function() {
      var expected = 'patch';
      var type;
      cManager.version.inc = function(newType) {
        type = newType;
      };
      spyOn(cManager.version, 'inc').and.callThrough();

      cManager.incVersion(expected);

      expect(cManager.version.inc).toHaveBeenCalled();
      expect(type).toEqual(expected);
    });

    describe('methods base on incVersion', function() {
      var type;

      beforeEach(function() {
        cManager.version.inc = function(newType) {
          type = newType;
        };
        spyOn(cManager.version, 'inc').and.callThrough();
      });

      it('should incPatch', function() {
        var expected = 'patch';

        cManager.incPatch();

        expect(cManager.version.inc).toHaveBeenCalled();
        expect(type).toEqual(expected);
      });

      it('should incMinor', function() {
        var expected = 'minor';

        cManager.incMminor();

        expect(cManager.version.inc).toHaveBeenCalled();
        expect(type).toEqual(expected);
      });

      it('should incMajor', function() {
        var expected = 'major';

        cManager.incMajor();

        expect(cManager.version.inc).toHaveBeenCalled();
        expect(type).toEqual(expected);
      });
    });
  });
});
<commit_msg>Update test<commit_after>'use strict';

var fs = require('fs');
var sh = require('shelljs');
var ConfigurationManager = require('../src/configuration-manager');

describe('Configuration manager', function() {
  var cManager = new ConfigurationManager();

  describe('methods with config', function() {
    var dirName = 'config/';
    var path = 'config/config.json';

    it('should run isExistOrCreate', function(done) {
      fs.exists(dirName, function (exists) {
        expect(exists).toBeFalsy();
      });
      cManager.configFile.isExistOrCreate = function() {
      };
      cManager.gitignore.update = function() {
      };
      spyOn(cManager.configFile, 'isExistOrCreate').and.callThrough();
      spyOn(cManager.gitignore, 'update').and.callThrough();

      cManager.init();

      expect(cManager.gitignore.update).toHaveBeenCalled();
      expect(cManager.configFile.isExistOrCreate).toHaveBeenCalled();

      fs.exists(path, function (exists) {
        expect(exists).toBeFalsy();
        done();
      });
    });

    it('should getConfig', function() {
      var expected = {
        a: 1,
        b: 2
      };
      cManager.configFile.get = function() {
        return expected;
      }
      spyOn(cManager.configFile, 'get').and.callThrough();

      var obj = cManager.getConfig();

      expect(cManager.configFile.get).toHaveBeenCalled();
      expect(obj).toEqual(expected);
    });

    it('should setConfig', function() {
      var expected = {
        a: 1,
        b: 2
      };
      cManager.configFile.set = function(obj) {
      }
      spyOn(cManager.configFile, 'set').and.callThrough();

      var obj = cManager.setConfig();

      expect(cManager.configFile.set).toHaveBeenCalled();
    });
  });

  describe('methods with version', function() {
    it('should getVersion', function() {
      cManager.version.get = function() {
        var v = '0.0.0';
        return v;
      };
      spyOn(cManager.version, 'get').and.callThrough();
      var expected = '0.0.0'

      var version = cManager.getVersion();

      expect(cManager.version.get).toHaveBeenCalled();
      expect(version).toEqual(expected);
    });

    it('should setVersion', function() {
      var version;
      cManager.version.set = function(newVersion) {
        version = newVersion;
      };
      spyOn(cManager.version, 'set').and.callThrough();
      var expected = '0.0.1'
      var value = '0.0.1';

      cManager.setVersion(value);

      expect(cManager.version.set).toHaveBeenCalled();
      expect(version).toEqual(expected);
    });

    describe('methods base on incVersion', function() {
      var type;

      beforeEach(function() {
        cManager.version.inc = function(newType) {
          type = newType;
        };
        spyOn(cManager.version, 'inc').and.callThrough();
      });

      it('should incVersion', function() {
        var expected = 'patch';

        cManager.incVersion(expected);

        expect(cManager.version.inc).toHaveBeenCalled();
        expect(type).toEqual(expected);
      });

      it('should incPatch', function() {
        var expected = 'patch';

        cManager.incPatch();

        expect(cManager.version.inc).toHaveBeenCalled();
        expect(type).toEqual(expected);
      });

      it('should incMinor', function() {
        var expected = 'minor';

        cManager.incMminor();

        expect(cManager.version.inc).toHaveBeenCalled();
        expect(type).toEqual(expected);
      });

      it('should incMajor', function() {
        var expected = 'major';

        cManager.incMajor();

        expect(cManager.version.inc).toHaveBeenCalled();
        expect(type).toEqual(expected);
      });
    });
  });
});
<|endoftext|>


<commit_before>/**
 *  Ajax Unique for jQuery, version 0.0
 *  (c) 2015 Peter Ragone, PRM Technologies, LLC
 *
 *  Ajax Autocomplete for jQuery is freely distributable under the terms of an MIT-style license.
 *  For details, see the web site: https://github.com/pcragone/simple_form_autocomplete
 */

/*jslint  browser: true, white: true, plusplus: true, vars: true */
/*global define, window, document, jQuery, exports, require */

// Expose plugin as an AMD module if AMD loader is present:
(function (factory) {
  'use strict';
  if (typeof define === 'function' && define.amd) {
    // AMD. Register as an anonymous module.
    define(['jquery'], factory);
  } else if (typeof exports === 'object' && typeof require === 'function') {
    // Browserify
    factory(require('jquery'));
  } else {
    // Browser globals
    factory(jQuery);
  }
}(function ($) {
  'use strict';

  var
    utils = (function () {
      return {
        escapeRegExChars: function (value) {
          return value.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
        },
        createNode: function (containerClass) {
          var div = document.createElement('div');
          div.className = containerClass;
          div.style.position = 'absolute';
          div.style.display = 'none';
          return div;
        },
        getFunctionByName: function (functionName, context /*, args */) {
          var args = Array.prototype.slice.call(arguments, 2);
          var namespaces = functionName.split(".");
          var func = namespaces.pop();
          for (var i = 0; i < namespaces.length; i++) {
            context = context[namespaces[i]];
          }
          return context[func];
        }
      };
    }()),

    keys = {
      ESC: 27,
      TAB: 9,
      RETURN: 13,
      LEFT: 37,
      UP: 38,
      RIGHT: 39,
      DOWN: 40
    };

  function UniqueInput(el, options) {
    var noop = function () { },
      that = this,
      defaults = {
        ajaxSettings: {},
        serviceUrl: null,
        minChars: 1,
        deferRequestBy: 0,
        params: {},
        formatResult: UniqueInput.formatResult,
        delimiter: null,
        type: 'GET',
        noCache: false,
        preserveInput: false,
        containerClass: 'autocomplete-suggestions',
        dataType: 'text',
        currentRequest: null,
        preventBadQueries: true,
        lookupFilter: function (suggestion, originalQuery, queryLowerCase) {
          return suggestion.value.toLowerCase().indexOf(queryLowerCase) !== -1;
        },
        paramName: $(el).data('param-name') || 'query',
        transformResult: function (response) {
          return typeof response === 'string' ? $.parseJSON(response) : response;
        },
        onSearchError: getFunctionByName($(el).data('on-search-error') || 'console.log', window)
      };

    // Shared variables:
    that.element = el;
    that.el = $(el);
    that.messageEl = that.el.siblings('.message');
    that.currentValue = that.element.value;
    that.options = $.extend({}, defaults, options);

    // Initialize and set options:
    that.initialize();
    //that.setOptions(options);
  }

  UniqueInput.utils = utils;

  $.UniqueInput = UniqueInput;

  UniqueInput.formatResult = function (suggestion, currentValue) {
    var escapedValue = utils.escapeRegExChars(currentValue);
    var pattern = "(" + escapedValue.split(' ').join('|') + ")";
    var regex = new RegExp(pattern, 'gi');
    var bolded = '<strong>$1<\/strong>';
    var value = suggestion.value;

    return value.replace(regex, bolded);
  };

  UniqueInput.prototype = {

    initialize: function () {
      var that = this,
        options = that.options,
        container;

      that.setParentPosition();

      that.el.on('keydown.uniqueInput', function (e) { that.onKeyPress(e); });
      that.el.on('keyup.uniqueInput', function (e) { that.onKeyUp(e); });
      that.el.on('blur.uniqueInput', function () { that.onBlur(); });
      that.el.on('focus.uniqueInput', function () { that.onFocus(); });
      that.el.on('change.uniqueInput', function (e) { that.onKeyUp(e); });
      that.el.on('input.uniqueInput', function (e) { that.onKeyUp(e); });
      that.options.serviceUrl = that.el.data('source');
      that.options.minChars = that.el.data('min-chars') || 1;
    },

    onFocus: function() {
      var that = this;
      that.storeCurrentValue();
    },

    onBlur: function() {
      var that = this;
      //that.validateUniqueness();
      that.clearCurrentValue();
    },

    onKeyPress: function(e) {
    },

    onKeyUp: function(e) {
      var that = this;

      if (that.disabled) {
        return;
      }

      clearInterval(that.onChangeInterval);

      if (that.currentValue !== that.el.val()) {
        if (that.options.deferRequestBy > 0) {
          // Defer lookup in case when value changes very quickly:
          that.onChangeInterval = setInterval(function () {
            that.onValueChange();
          }, that.options.deferRequestBy);
        } else {
          that.onValueChange();
        }
      }
    },

    onValueChange: function () {
      var that = this,
        options = that.options,
        value = that.el.val(),
        query = that.getQuery(value),
        index;

      clearInterval(that.onChangeInterval);
      that.currentValue = value;

      if (value == that.el.data('original-value')) {
        that.showAvailableMessage();
        return;
      }

      if (query.length < options.minChars) {
      } else {
        that.validateUniqueness(query);
      }
    },

    getQuery: function (value) {
      var delimiter = this.options.delimiter,
        parts;

      if (!delimiter) {
        return value;
      }
      parts = value.split(delimiter);
      return $.trim(parts[parts.length - 1]);
    },

    validateUniqueness: function(q) {
      var response,
        that = this,
        options = that.options,
        serviceUrl = options.serviceUrl,
        params,
        cacheKey,
        ajaxSettings;
      options.params[options.paramName] = q;
      params = options.ignoreParams ? null : options.params;

      params['id'] = that.el.data('object-id');

      if (that.currentRequest) {
        that.currentRequest.abort();
      }

      ajaxSettings = {
        url: serviceUrl,
        data: params,
        type: options.type,
        dataType: options.dataType
      };

      $.extend(ajaxSettings, options.ajaxSettings);
      that.setLoadingMessage();

      that.currentRequest = $.ajax(ajaxSettings).done(function (data) {
        var result;
        that.currentRequest = null;
        result = options.transformResult(data);
        if (result['unique'] === true) {
          that.showAvailableMessage();
        }

        if (result['unique'] === false) {
          that.showUnavailableMessage();
        }
        //that.processResponse(result, q, cacheKey);
        //options.onSearchComplete.call(that.element, q, result.suggestions);
      }).fail(function (jqXHR, textStatus, errorThrown) {
        options.onSearchError.call(that.element, q, jqXHR, textStatus, errorThrown);
      });
    },

    processResponse: function (result, originalQuery, cacheKey) {
        var that = this,
        options = that.options;
    },

    storeCurrentValue: function() {
      var that = this;
      that.currentValue = that.el.val();
      return;
    },

    clearCurrentValue: function() {
      var that = this;
      that.currentValue = undefined;
      return;
    },

    setParentPosition: function() {
      var that = this,
        parentEl = that.el.parent();
      // Add a position value to the parent element so we can set the position of the available/unavailable message
      if (parentEl.css('position') === 'static')
        parentEl.css('position', 'relative');
    },

    setLoadingMessage: function () {
      var that = this;
      that.el.parent().parent().removeClass('has-success');
      that.el.parent().parent().removeClass('has-error');
      that.el.parent().siblings('.help-block').remove()
      that.messageEl.removeClass('available');
      that.messageEl.removeClass('unavailable');
      that.messageEl.html('Loading...');
    },

    showAvailableMessage: function () {
      var that = this;
      that.el.parent().parent().removeClass('has-success');
      that.el.parent().parent().removeClass('has-error');
      that.messageEl.removeClass('available');
      that.messageEl.removeClass('unavailable');
      that.el.parent().parent().addClass('has-success');
      that.messageEl.html('Available');
      that.messageEl.addClass('available');
    },

    showUnavailableMessage: function () {
      var that = this;
      that.el.parent().parent().removeClass('has-success');
      that.el.parent().parent().removeClass('has-error');
      that.messageEl.removeClass('available');
      that.messageEl.removeClass('unavailable');
      that.el.parent().parent().addClass('has-error');
      that.messageEl.html('Unavailable');
      that.messageEl.addClass('unavailable');
    }

  };

  // Create chainable jQuery plugin:
  $.fn.unique_input = function (options, args) {
    var dataKey = 'unique';
    // If function invoked without argument return
    // instance of the first matched element:
    if (arguments.length === 0) {
      return this.first().data(dataKey);
    }

    return this.each(function () {
      var inputElement = $(this),
        instance = inputElement.data(dataKey);

      if (typeof options === 'string') {
        if (instance && typeof instance[options] === 'function') {
          instance[options](args);
        }
      } else {
        // If instance already exists, destroy it:
        if (instance && instance.dispose) {
          instance.dispose();
        }
        instance = new UniqueInput(this, options);
        inputElement.data(dataKey, instance);
      }
    });
  };
}));

window.uniqueInput = function(input){
  $(input).unique_input({});
};

uniqueInputInit = function(){
  $('input.simple_form_unique').each(function(index, input) {
    window.uniqueInput(input);
  });
};

$(document).ready(uniqueInputInit);
$(document).on('page:load', uniqueInputInit);
<commit_msg>Fixes javascript reference to the correct method.<commit_after>/**
 *  Ajax Unique for jQuery, version 0.0
 *  (c) 2015 Peter Ragone, PRM Technologies, LLC
 *
 *  Ajax Autocomplete for jQuery is freely distributable under the terms of an MIT-style license.
 *  For details, see the web site: https://github.com/pcragone/simple_form_autocomplete
 */

/*jslint  browser: true, white: true, plusplus: true, vars: true */
/*global define, window, document, jQuery, exports, require */

// Expose plugin as an AMD module if AMD loader is present:
(function (factory) {
  'use strict';
  if (typeof define === 'function' && define.amd) {
    // AMD. Register as an anonymous module.
    define(['jquery'], factory);
  } else if (typeof exports === 'object' && typeof require === 'function') {
    // Browserify
    factory(require('jquery'));
  } else {
    // Browser globals
    factory(jQuery);
  }
}(function ($) {
  'use strict';

  var
    utils = (function () {
      return {
        escapeRegExChars: function (value) {
          return value.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
        },
        createNode: function (containerClass) {
          var div = document.createElement('div');
          div.className = containerClass;
          div.style.position = 'absolute';
          div.style.display = 'none';
          return div;
        },
        getFunctionByName: function (functionName, context /*, args */) {
          var args = Array.prototype.slice.call(arguments, 2);
          var namespaces = functionName.split(".");
          var func = namespaces.pop();
          for (var i = 0; i < namespaces.length; i++) {
            context = context[namespaces[i]];
          }
          return context[func];
        }
      };
    }()),

    keys = {
      ESC: 27,
      TAB: 9,
      RETURN: 13,
      LEFT: 37,
      UP: 38,
      RIGHT: 39,
      DOWN: 40
    };

  function UniqueInput(el, options) {
    var noop = function () { },
      that = this,
      defaults = {
        ajaxSettings: {},
        serviceUrl: null,
        minChars: 1,
        deferRequestBy: 0,
        params: {},
        formatResult: UniqueInput.formatResult,
        delimiter: null,
        type: 'GET',
        noCache: false,
        preserveInput: false,
        containerClass: 'autocomplete-suggestions',
        dataType: 'text',
        currentRequest: null,
        preventBadQueries: true,
        lookupFilter: function (suggestion, originalQuery, queryLowerCase) {
          return suggestion.value.toLowerCase().indexOf(queryLowerCase) !== -1;
        },
        paramName: $(el).data('param-name') || 'query',
        transformResult: function (response) {
          return typeof response === 'string' ? $.parseJSON(response) : response;
        },
        onSearchError: utils.getFunctionByName($(el).data('on-search-error') || 'console.log', window)
      };

    // Shared variables:
    that.element = el;
    that.el = $(el);
    that.messageEl = that.el.siblings('.message');
    that.currentValue = that.element.value;
    that.options = $.extend({}, defaults, options);

    // Initialize and set options:
    that.initialize();
    //that.setOptions(options);
  }

  UniqueInput.utils = utils;

  $.UniqueInput = UniqueInput;

  UniqueInput.formatResult = function (suggestion, currentValue) {
    var escapedValue = utils.escapeRegExChars(currentValue);
    var pattern = "(" + escapedValue.split(' ').join('|') + ")";
    var regex = new RegExp(pattern, 'gi');
    var bolded = '<strong>$1<\/strong>';
    var value = suggestion.value;

    return value.replace(regex, bolded);
  };

  UniqueInput.prototype = {

    initialize: function () {
      var that = this,
        options = that.options,
        container;

      that.setParentPosition();

      that.el.on('keydown.uniqueInput', function (e) { that.onKeyPress(e); });
      that.el.on('keyup.uniqueInput', function (e) { that.onKeyUp(e); });
      that.el.on('blur.uniqueInput', function () { that.onBlur(); });
      that.el.on('focus.uniqueInput', function () { that.onFocus(); });
      that.el.on('change.uniqueInput', function (e) { that.onKeyUp(e); });
      that.el.on('input.uniqueInput', function (e) { that.onKeyUp(e); });
      that.options.serviceUrl = that.el.data('source');
      that.options.minChars = that.el.data('min-chars') || 1;
    },

    onFocus: function() {
      var that = this;
      that.storeCurrentValue();
    },

    onBlur: function() {
      var that = this;
      //that.validateUniqueness();
      that.clearCurrentValue();
    },

    onKeyPress: function(e) {
    },

    onKeyUp: function(e) {
      var that = this;

      if (that.disabled) {
        return;
      }

      clearInterval(that.onChangeInterval);

      if (that.currentValue !== that.el.val()) {
        if (that.options.deferRequestBy > 0) {
          // Defer lookup in case when value changes very quickly:
          that.onChangeInterval = setInterval(function () {
            that.onValueChange();
          }, that.options.deferRequestBy);
        } else {
          that.onValueChange();
        }
      }
    },

    onValueChange: function () {
      var that = this,
        options = that.options,
        value = that.el.val(),
        query = that.getQuery(value),
        index;

      clearInterval(that.onChangeInterval);
      that.currentValue = value;

      if (value == that.el.data('original-value')) {
        that.showAvailableMessage();
        return;
      }

      if (query.length < options.minChars) {
      } else {
        that.validateUniqueness(query);
      }
    },

    getQuery: function (value) {
      var delimiter = this.options.delimiter,
        parts;

      if (!delimiter) {
        return value;
      }
      parts = value.split(delimiter);
      return $.trim(parts[parts.length - 1]);
    },

    validateUniqueness: function(q) {
      var response,
        that = this,
        options = that.options,
        serviceUrl = options.serviceUrl,
        params,
        cacheKey,
        ajaxSettings;
      options.params[options.paramName] = q;
      params = options.ignoreParams ? null : options.params;

      params['id'] = that.el.data('object-id');

      if (that.currentRequest) {
        that.currentRequest.abort();
      }

      ajaxSettings = {
        url: serviceUrl,
        data: params,
        type: options.type,
        dataType: options.dataType
      };

      $.extend(ajaxSettings, options.ajaxSettings);
      that.setLoadingMessage();

      that.currentRequest = $.ajax(ajaxSettings).done(function (data) {
        var result;
        that.currentRequest = null;
        result = options.transformResult(data);
        if (result['unique'] === true) {
          that.showAvailableMessage();
        }

        if (result['unique'] === false) {
          that.showUnavailableMessage();
        }
        //that.processResponse(result, q, cacheKey);
        //options.onSearchComplete.call(that.element, q, result.suggestions);
      }).fail(function (jqXHR, textStatus, errorThrown) {
        options.onSearchError.call(that.element, q, jqXHR, textStatus, errorThrown);
      });
    },

    processResponse: function (result, originalQuery, cacheKey) {
        var that = this,
        options = that.options;
    },

    storeCurrentValue: function() {
      var that = this;
      that.currentValue = that.el.val();
      return;
    },

    clearCurrentValue: function() {
      var that = this;
      that.currentValue = undefined;
      return;
    },

    setParentPosition: function() {
      var that = this,
        parentEl = that.el.parent();
      // Add a position value to the parent element so we can set the position of the available/unavailable message
      if (parentEl.css('position') === 'static')
        parentEl.css('position', 'relative');
    },

    setLoadingMessage: function () {
      var that = this;
      that.el.parent().parent().removeClass('has-success');
      that.el.parent().parent().removeClass('has-error');
      that.el.parent().siblings('.help-block').remove()
      that.messageEl.removeClass('available');
      that.messageEl.removeClass('unavailable');
      that.messageEl.html('Loading...');
    },

    showAvailableMessage: function () {
      var that = this;
      that.el.parent().parent().removeClass('has-success');
      that.el.parent().parent().removeClass('has-error');
      that.messageEl.removeClass('available');
      that.messageEl.removeClass('unavailable');
      that.el.parent().parent().addClass('has-success');
      that.messageEl.html('Available');
      that.messageEl.addClass('available');
    },

    showUnavailableMessage: function () {
      var that = this;
      that.el.parent().parent().removeClass('has-success');
      that.el.parent().parent().removeClass('has-error');
      that.messageEl.removeClass('available');
      that.messageEl.removeClass('unavailable');
      that.el.parent().parent().addClass('has-error');
      that.messageEl.html('Unavailable');
      that.messageEl.addClass('unavailable');
    }

  };

  // Create chainable jQuery plugin:
  $.fn.unique_input = function (options, args) {
    var dataKey = 'unique';
    // If function invoked without argument return
    // instance of the first matched element:
    if (arguments.length === 0) {
      return this.first().data(dataKey);
    }

    return this.each(function () {
      var inputElement = $(this),
        instance = inputElement.data(dataKey);

      if (typeof options === 'string') {
        if (instance && typeof instance[options] === 'function') {
          instance[options](args);
        }
      } else {
        // If instance already exists, destroy it:
        if (instance && instance.dispose) {
          instance.dispose();
        }
        instance = new UniqueInput(this, options);
        inputElement.data(dataKey, instance);
      }
    });
  };
}));

window.uniqueInput = function(input){
  $(input).unique_input({});
};

uniqueInputInit = function(){
  $('input.simple_form_unique').each(function(index, input) {
    window.uniqueInput(input);
  });
};

$(document).ready(uniqueInputInit);
$(document).on('page:load', uniqueInputInit);
<|endoftext|>


<commit_before>'use strict';

var gulp = require('gulp');
var sass = require('gulp-sass');

var root_input = './{{cookiecutter.project_slug}}/static_src/';
var root_output = './{{cookiecutter.project_slug}}/static/';

var sourcemaps = require('gulp-sourcemaps');
var refresh = require('gulp-refresh');

gulp.task('sass', function () {
  return gulp.src(root_input + "sass/base.scss")
      .pipe(sourcemaps.init())
    .pipe(sass().on('error', sass.logError))
      .pipe(sourcemaps.write("sourcemaps/"))
    .pipe(gulp.dest(root_output + "css"))
      .pipe(refresh());
});

const imagemin = require('gulp-imagemin');
gulp.task('images', function(cb) {
    gulp.src(root_input + 'images/*')
        .pipe(imagemin())
        .pipe(gulp.dest(root_output + 'images'))
});

gulp.task('logo', function(cb) {
    gulp.src(root_input + 'logo/*')
        .pipe(imagemin())
        .pipe(gulp.dest(root_output + 'logo'))
});

gulp.task('icons', function(cb) {
    gulp.src(root_input + 'icons/*')
        .pipe(imagemin())
        .pipe(gulp.dest(root_output + 'icons'))
});

gulp.task('image_playground', function(cb) {
    gulp.src(root_input + 'image_playground/input/*')
        .pipe(imagemin())
        .pipe(gulp.dest(root_input + 'image_playground/output'))
});

var uglify = require('gulp-uglify');

gulp.task('js', function() {
  gulp.src(root_input + 'js/**/*.js')
      .pipe(sourcemaps.init())
    .pipe(uglify())
      .pipe(sourcemaps.write("sourcemaps/"))
    .pipe(gulp.dest(root_output + 'js'))
    .pipe(refresh())
});

gulp.task('watch', function () {
    refresh.listen();
  gulp.watch(root_input + "sass/**/*.scss", ['sass']);
  gulp.watch(root_input + "js/**/*.js", ['js']);
});

gulp.task('default', ['sass', 'js', 'watch'])
gulp.task('img', ['images', 'logo', 'icons'])<commit_msg>Auto refresh templates<commit_after>'use strict';

var gulp = require('gulp');
var sass = require('gulp-sass');

var root_input = './{{cookiecutter.project_slug}}/static_src/';
var root_output = './{{cookiecutter.project_slug}}/static/';

var sourcemaps = require('gulp-sourcemaps');
var refresh = require('gulp-refresh');

gulp.task('sass', function () {
  return gulp.src(root_input + "sass/base.scss")
      .pipe(sourcemaps.init())
    .pipe(sass().on('error', sass.logError))
      .pipe(sourcemaps.write("sourcemaps/"))
    .pipe(gulp.dest(root_output + "css"))
      .pipe(refresh());
});

const imagemin = require('gulp-imagemin');
gulp.task('images', function(cb) {
    gulp.src(root_input + 'images/*')
        .pipe(imagemin())
        .pipe(gulp.dest(root_output + 'images'))
});

gulp.task('logo', function(cb) {
    gulp.src(root_input + 'logo/*')
        .pipe(imagemin())
        .pipe(gulp.dest(root_output + 'logo'))
});

gulp.task('icons', function(cb) {
    gulp.src(root_input + 'icons/*')
        .pipe(imagemin())
        .pipe(gulp.dest(root_output + 'icons'))
});

gulp.task('image_playground', function(cb) {
    gulp.src(root_input + 'image_playground/input/*')
        .pipe(imagemin())
        .pipe(gulp.dest(root_input + 'image_playground/output'))
});

var uglify = require('gulp-uglify');

gulp.task('js', function() {
  gulp.src(root_input + 'js/**/*.js')
      .pipe(sourcemaps.init())
    .pipe(uglify())
      .pipe(sourcemaps.write("sourcemaps/"))
    .pipe(gulp.dest(root_output + 'js'))
    .pipe(refresh())
});

gulp.task('watch', function () {
    refresh.listen();
  gulp.watch(root_input + "sass/**/*.scss", ['sass']);
  gulp.watch(root_input + "js/**/*.js", ['js']);
  gulp.watch(root_input + "../templates/**/*.html").on("change", refresh.reload);
});

gulp.task('default', ['sass', 'js', 'watch'])
gulp.task('img', ['images', 'logo', 'icons'])<|endoftext|>


<commit_before>/**
 * @fileoverview Check for duplicated dependent keys for observers and computed properties
 * @author onechiporenko
 * @copyright 2016 onechiporenko. All rights reserved.
 * See LICENSE file in root directory for full license.
 */
"use strict";
var ember = require("../utils/ember.js");
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------

module.exports = function(context) {

  var options = context.options[0] || {};
  var tryExpandKeys = options.tryExpandKeys;

  //--------------------------------------------------------------------------
  // Public
  //--------------------------------------------------------------------------

  return {
    "CallExpression": function (node) {
      if (ember.isEmberField(node)) {
        var keys = ember.getDependentKeys(node);
        var uniqueKeys = ember.getDependentKeys(node, true);
        if (tryExpandKeys) {
          keys = ember.expandDependentKeys(keys);
          uniqueKeys = ember.expandDependentKeys(keys, true);
        }
        if (keys && uniqueKeys && keys.length !== uniqueKeys.length) {
          context.report(node, "Some dependent keys are duplicated.");
        }
      }
    }
  };

};

module.exports.schema = [
  {
    type: "object",
    properties: {
      tryExpandKeys: {
        type: "boolean"
      }
    },
    additionalProperties: false
  }
];<commit_msg>Small improve for `no-dup-keys`<commit_after>/**
 * @fileoverview Check for duplicated dependent keys for observers and computed properties
 * @author onechiporenko
 * @copyright 2016 onechiporenko. All rights reserved.
 * See LICENSE file in root directory for full license.
 */
"use strict";
var ember = require("../utils/ember.js");
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------

module.exports = function(context) {

  var options = context.options[0] || {};
  var tryExpandKeys = options.tryExpandKeys;

  function onlyUnique(value, index, self) {
    return self.indexOf(value) === index;
  }

  //--------------------------------------------------------------------------
  // Public
  //--------------------------------------------------------------------------

  return {
    "CallExpression": function (node) {
      if (ember.isEmberField(node)) {
        var keys = ember.getDependentKeys(node);
        var uniqueKeys = keys.filter(onlyUnique);
        if (tryExpandKeys) {
          keys = ember.expandDependentKeys(keys);
          uniqueKeys = keys.filter(onlyUnique);
        }
        if (keys && uniqueKeys && keys.length !== uniqueKeys.length) {
          context.report(node, "Some dependent keys are duplicated.");
        }
      }
    }
  };

};

module.exports.schema = [
  {
    type: "object",
    properties: {
      tryExpandKeys: {
        type: "boolean"
      }
    },
    additionalProperties: false
  }
];<|endoftext|>


<commit_before>'use strict';

var request = require('superagent');
var Events = require('./events');

/**
 * HttpClient
 * @exports CamSDK.HttpClientMock
 * @augments {CamSDK.HttpClient}
 * @class
 * @classdesc A mocking implementation of CamSDK.HttpClient
 */
var HttpClient = function(config) {
  config = config || {};

  if (!config.baseUrl) {
    throw new Error('HttpClientMock needs a `baseUrl` configuration property.');
  }

  Events.attach(this);

  this.config = config;

  this.mock = true;
};

/**
 * Variable to store fixtures
 * @type {Object}
 * @property {Object.<uuid, Object>} processDefinition  Process definition mocks
 * @property {Object.<uuid, Object>} processInstance    Process instance mocks
 * @property {Object.<uuid, Object>} user               User mocks
 * @property {Object.<uuid, Object>} variable           Variable mocks
 */
var _store = {};
var fixturer = require('fixturer');
var uuid = require('uuid');
var _ = require('underscore');
_.str = require('underscore.string');

var i = 0, id;
_store.processDefinition = {};
for (; i < 80; i++) {
  id = uuid();
  _store.processDefinition[id] = {
    id: id,
    key: fixturer.randomString(fixturer.random(8, 16)),
    // name: fixturer.thingName(),
    name: fixturer.randomItem([
      'Call Process '+ i,
      'process '+ i,
      'yada '+ i,
      'foo Bar '+ i,
      'Foo-Bar '+ i
    ]),
    resource: fixturer.randomString(fixturer.random(4, 8)),
    diagram: fixturer.randomString(fixturer.random(4, 8)),
    version: fixturer.random(),
    deploymentId: uuid(),
    suspended: !!fixturer.random(0, 1),
    category: fixturer.randomItem([
      'category1',
      'category2',
      'category3',
      'category4',
      'category5'
    ], 1)
  };
}

_store.user = {};
for (i = 0; i < 40; i++) {
  id = fixturer.randomString(4, 8);
  _store.user[id] = {
    id: id,
    firstName: fixturer.personName(true, false),
    lastName: fixturer.personName(false, true),
    email: fixturer.randomString(4, 8) +'@'+ fixturer.randomString(5, 7) +'.com'
  };
}
_store.user.jonny1 = {
  id: 'jonny1',
  firstName: 'Jonny',
  lastName: 'One',
  email: fixturer.randomString(4, 8) +'@'+ fixturer.randomString(5, 7) +'.com'
};

_store.processInstance = {};
for (var processDefinitionId in _store.processDefinition) {
  var count = fixturer.random(0, 80);
  for (i = 0; i < count; i++) {
    id = uuid();
    _store.processInstance[id] = {
      links: [],
      id: id,
      definitionId: processDefinitionId,
      businessKey: fixturer.randomString(8, 16),
      ended: !!fixturer.random(0, 1),
      suspended: !!fixturer.random(0, 1)
    };
  }
}

var users = _.keys(_store.user);
users.push(null);

var procInst, procInstId;
var procInstances = _.keys(_store.processInstance);
// procInstances.push(null);

_store.task = {};
for (i = 0; i < 300; i++) {
  id = uuid();
  procInstId = fixturer.randomItem(procInstances);
  procInst = _store.processInstance[procInstId];
  var created = fixturer.randomDate(new Date('1.1.2014'), new Date());

  _store.task[id] = {
    id: id,
    name: fixturer.thingName(fixturer.random(2, 12)),
    assignee: fixturer.randomItem(users),
    created: created,
    due: fixturer.randomDate(created, new Date('11.29.2014')),
    followUp: fixturer.randomDate(created, new Date('10.29.2014')),
    delegationState: 'RESOLVED',
    description: fixturer.thingName(fixturer.random(7, 42)),
    executionId: uuid(),
    owner: fixturer.randomItem(users),
    // should link to a existing task.id
    parentTaskId: null,
    priority: fixturer.random(),
    processDefinitionId: procInst.definitionId,
    processInstanceId: procInstId,
    taskDefinitionKey: 'Task_'+ fixturer.random(1, 20)
  };
}

var subId;
for (id in  _store.task) {
  if (fixturer.random(1, 6) > 3) {
    subId = uuid();
    procInstId = _store.task[id].processInstanceId;
    procInst = _store.processInstance[procInstId];

    _store.task[subId] = {
      id: subId,
      name: fixturer.thingName(),
      assignee: fixturer.randomItem(users),
      created: '2013-01-23T13:42:42',
      due: '2013-01-23T13:49:42',
      followUp: '2013-01-23T13:44:42',
      delegationState: 'RESOLVED',
      description: 'aDescription',
      executionId: uuid(),
      owner: fixturer.randomItem(users),
      // should link to a existing task.id
      parentTaskId: id,
      priority: fixturer.random(),
      processDefinitionId: procInst.definitionId,
      processInstanceId: procInstId,
      taskDefinitionKey: null
    };
  }
}

_store.variable = {};
for (i = 0; i < 600; i++) {
  id = uuid();
  _store.variable[id] = {
    id: id,
    name: fixturer.randomString(4, 16),
    type: fixturer.randomItem([
      'integer',
      'double',
      'string'
    ]),
    value: 5,
    processInstanceId: null,
    executionId: uuid(),
    taskId: null,
    activityInstanceId: 'Task_1:b68b71ca-e310-11e2-beb0-f0def1557726'
  };
}

_store.pile = {};
_.each([
  {
    id: uuid(),
    name: 'Mines',
    description: '',
    filters: [
      {
        key: 'assignee',
        value: '{self}'
      }
    ],
    color: '#AFB3E2'
  },
  {
    id: uuid(),
    name: 'Overdue',
    description: '',
    filters: [
      {
        key: 'due',
        operator: 'smaller',
        value: '{now}'
      }
    ],
    color: '#FFB4B4'
  },
  {
    id: uuid(),
    name: 'Due in 3 days',
    description: '',
    filters: [
      {
        key: 'due',
        operator: 'smaller',
        value: '{now} + ({day} * 3)'
      }
    ],
    color: '#FFD2D2'
  },
  {
    id: uuid(),
    name: 'Group A',
    description: '',
    filters: [
      {
        key: 'identityLink',
        operator: 'has',
        value: 'group-a'
      }
    ],
    color: ''
  },
  {
    id: uuid(),
    name: 'Group B',
    description: '',
    filters: [
      {
        key: 'identityLink',
        operator: 'has',
        value: 'group-a'
      }
    ],
    color: ''
  }
], function(pile) {
  _store.pile[pile.id] = pile;
});

function inPath(expected, given) {
  return given.slice(0, expected.length) === expected;
}

function filter(src, data) {
  var where = {
    exact: {},
    like: {}
  };
  var notFilters = [
    'sortBy',
    'sortOrder',
    'firstResult',
    'maxResults'
  ];

  var likeExp = /Like$/;
  _.each(data, function(val, key) {
    if (notFilters.indexOf(key) > -1) { return; }

    var isLike = likeExp.test(key);
    where[isLike ? 'like' : 'exact'][key] = isLike ? new RegExp((''+ val).slice(1).slice(0, -1), 'g') : val;
  });

  var found = _.size(where.exact) ? _.where(src, where.exact) : _.toArray(src);

  found = _.size(where.like) ? _.filter(found, function(item) {
    var keep = true;
    var realKey;
    _.each(where.like, function(search, key) {
      if (!keep) { return; }
      realKey = key.slice(0, -4);
      keep = search.test(''+ item[key.slice(0, -4)]);
    });
    return keep;
  }) : found;

  return found;
}

function genericGet(wanted, items, where) {
  var returned;

  if (wanted === 'key') {
    returned = _.findWhere(items, {key: wanted});
  }

  else if (!wanted || wanted === 'count') {
    // var safe = _.clone(where);
    // delete safe.maxResults;
    // delete safe.firstResult;
    // delete safe.sortBy;
    // delete safe.sortOrder;
    returned = filter(items, where);

    // returns an object with "count"
    if (wanted) {
      returned = { count: returned.length };
    }
    // returns an aray of items
    else {
      var offset = parseInt(where.firstResult || 0, 10);
      var limit = offset + parseInt(where.maxResults || 10, 10);
      returned = _.toArray(returned).slice(offset, limit);
    }
  }

  // request by id
  else if (wanted) {
    returned = items[wanted];
  }

  return returned;
}

/**
 * Performs a POST HTTP request
 */
HttpClient.prototype.post = function(path, options) {
  options = options || {};

  var done = options.done || function() {};
  var results;

  var pathParts = path.split('/');
  var resourceName = pathParts.shift();
  console.info('SDK MOCKING: "POST" request on "'+ resourceName +'"', pathParts.join(', '), options.data);

  switch (resourceName) {
    case 'process-definition':
      var action = pathParts[pathParts.length - 1];
      var definition;
      if (pathParts[0] === 'key') {
        definition = _.findWhere(_store.processDefinition, {key: pathParts[1]});
      }
      else {
        definition = _store.processDefinition[pathParts[0]];
      }

      switch (action) {
        case 'submit-form':
          var id = uuid();
          _store.processInstance[id] = {
            id: id,
            definitionId: definition.id,
            businessKey: 'myBusinessKey',
            ended: false,
            suspended: false
          };

          results = _.extend({
            links:[
              {
                method: 'GET',
                href: 'http://localhost:8080/rest-test/process-instance/'+ id,
                rel: 'self'
              }
            ],
          }, _store.processInstance[id]);
          break;
      }
      break;
  }

  // postpone the response to simulate latency
  setTimeout(function() {
    done(null, results);
  }, fixturer.random(50, 400));
};

/**
 * Performs a GET HTTP request
 */
HttpClient.prototype.get = function(path, options) {
  options = options || {};

  var done = options.done || function() {};
  var results;

  var pathParts = path.split('/');
  var resourceName = pathParts.shift();
  console.info('SDK MOCKING: "GET" request on "'+ resourceName +'"', pathParts.join(', '));

  switch (resourceName) {
    case 'process-definition':
      results = genericGet(pathParts[0], _store.processDefinition, options.data);
      break;

    case 'process-instance':
      results = genericGet(pathParts[0], _store.processInstance, options.data);
      break;

    case 'pile':
      results = genericGet(pathParts[0], _store.pile, options.data);
      break;

    case 'task':
      results = genericGet(pathParts[0], _store.task, options.data);
      break;

    case 'user':
      results = genericGet(pathParts[0], _store.user, options.data);
      break;

    case 'variable-instance':
      results = genericGet(pathParts[0], _store.variable, options.data);
      break;
  }

  // postpone the response to simulate latency
  setTimeout(function() {
    done(null, results);
  }, fixturer.random(50, 400));
};

/**
 * Performs a PUT HTTP request
 */
HttpClient.prototype.put = function(path, options) {
  options = options || {};
  var done = options.done || function() {};
  var results = {};

  done(null, { body: results });
};

/**
 * Performs a DELETE HTTP request
 */
HttpClient.prototype.del = function(data, options) {
  data = data || {};
  options = options || {};
};
module.exports = HttpClient;
<commit_msg>improve(mock): add after and before filtering<commit_after>'use strict';

var request = require('superagent');
var Events = require('./events');

/**
 * HttpClient
 * @exports CamSDK.HttpClientMock
 * @augments {CamSDK.HttpClient}
 * @class
 * @classdesc A mocking implementation of CamSDK.HttpClient
 */
var HttpClient = function(config) {
  config = config || {};

  if (!config.baseUrl) {
    throw new Error('HttpClientMock needs a `baseUrl` configuration property.');
  }

  Events.attach(this);

  this.config = config;

  this.mock = true;
};

/**
 * Variable to store fixtures
 * @type {Object}
 * @property {Object.<uuid, Object>} processDefinition  Process definition mocks
 * @property {Object.<uuid, Object>} processInstance    Process instance mocks
 * @property {Object.<uuid, Object>} user               User mocks
 * @property {Object.<uuid, Object>} variable           Variable mocks
 */
var _store = {};
var fixturer = require('fixturer');
var uuid = require('uuid');
var _ = require('underscore');
_.str = require('underscore.string');

var i = 0, id;
_store.processDefinition = {};
for (; i < 80; i++) {
  id = uuid();
  _store.processDefinition[id] = {
    id: id,
    key: fixturer.randomString(fixturer.random(8, 16)),
    // name: fixturer.thingName(),
    name: fixturer.randomItem([
      'Call Process '+ i,
      'process '+ i,
      'yada '+ i,
      'foo Bar '+ i,
      'Foo-Bar '+ i
    ]),
    resource: fixturer.randomString(fixturer.random(4, 8)),
    diagram: fixturer.randomString(fixturer.random(4, 8)),
    version: fixturer.random(),
    deploymentId: uuid(),
    suspended: !!fixturer.random(0, 1),
    category: fixturer.randomItem([
      'category1',
      'category2',
      'category3',
      'category4',
      'category5'
    ], 1)
  };
}

_store.user = {};
for (i = 0; i < 40; i++) {
  id = fixturer.randomString(4, 8);
  _store.user[id] = {
    id: id,
    firstName: fixturer.personName(true, false),
    lastName: fixturer.personName(false, true),
    email: fixturer.randomString(4, 8) +'@'+ fixturer.randomString(5, 7) +'.com'
  };
}
_store.user.jonny1 = {
  id: 'jonny1',
  firstName: 'Jonny',
  lastName: 'One',
  email: fixturer.randomString(4, 8) +'@'+ fixturer.randomString(5, 7) +'.com'
};

_store.processInstance = {};
for (var processDefinitionId in _store.processDefinition) {
  var count = fixturer.random(0, 80);
  for (i = 0; i < count; i++) {
    id = uuid();
    _store.processInstance[id] = {
      links: [],
      id: id,
      definitionId: processDefinitionId,
      businessKey: fixturer.randomString(8, 16),
      ended: !!fixturer.random(0, 1),
      suspended: !!fixturer.random(0, 1)
    };
  }
}

var users = _.keys(_store.user);
users.push(null);

var procInst, procInstId;
var procInstances = _.keys(_store.processInstance);
// procInstances.push(null);

_store.task = {};
for (i = 0; i < 300; i++) {
  id = uuid();
  procInstId = fixturer.randomItem(procInstances);
  procInst = _store.processInstance[procInstId];
  var created = fixturer.randomDate(new Date('1.1.2014'), new Date());

  _store.task[id] = {
    id: id,
    name: fixturer.thingName(fixturer.random(2, 12)),
    assignee: fixturer.randomItem(users),
    created: created,
    due: fixturer.randomDate(created, new Date('11.29.2014')),
    followUp: fixturer.randomDate(created, new Date('10.29.2014')),
    delegationState: 'RESOLVED',
    description: fixturer.thingName(fixturer.random(7, 42)),
    executionId: uuid(),
    owner: fixturer.randomItem(users),
    // should link to a existing task.id
    parentTaskId: null,
    priority: fixturer.random(),
    processDefinitionId: procInst.definitionId,
    processInstanceId: procInstId,
    taskDefinitionKey: 'Task_'+ fixturer.random(1, 20)
  };
}

var subId;
for (id in  _store.task) {
  if (fixturer.random(1, 6) > 3) {
    var created = fixturer.randomDate(new Date('1.1.2014'), new Date());
    subId = uuid();
    procInstId = _store.task[id].processInstanceId;
    procInst = _store.processInstance[procInstId];

    _store.task[subId] = {
      id: subId,
      name: fixturer.thingName(),
      assignee: fixturer.randomItem(users),
      created: created,
      due: fixturer.randomDate(created, new Date('11.29.2014')),
      followUp: fixturer.randomDate(created, new Date('10.29.2014')),
      delegationState: 'RESOLVED',
      description: fixturer.thingName(fixturer.random(7, 42)),
      executionId: uuid(),
      owner: fixturer.randomItem(users),
      // should link to a existing task.id
      parentTaskId: id,
      priority: fixturer.random(),
      processDefinitionId: procInst.definitionId,
      processInstanceId: procInstId,
      taskDefinitionKey: null
    };
  }
}

_store.variable = {};
for (i = 0; i < 600; i++) {
  id = uuid();
  _store.variable[id] = {
    id: id,
    name: fixturer.randomString(4, 16),
    type: fixturer.randomItem([
      'integer',
      'double',
      'string'
    ]),
    value: 5,
    processInstanceId: null,
    executionId: uuid(),
    taskId: null,
    activityInstanceId: 'Task_1:b68b71ca-e310-11e2-beb0-f0def1557726'
  };
}

_store.pile = {};
_.each([
  {
    id: uuid(),
    name: 'Mines',
    description: '',
    filters: [
      {
        key: 'assignee',
        value: '{self}'
      }
    ],
    color: '#AFB3E2'
  },
  {
    id: uuid(),
    name: 'Overdue',
    description: '',
    filters: [
      {
        key: 'dueBefore',
        // operator: 'smaller',
        value: '{now}'
      }
    ],
    color: '#FFB4B4'
  },
  {
    id: uuid(),
    name: 'Due in 3 days',
    description: '',
    filters: [
      {
        key: 'dueBefore',
        // operator: 'smaller',
        value: '{now} + ({day} * 3)'
      }
    ],
    color: '#FFD2D2'
  },
  {
    id: uuid(),
    name: 'Group A',
    description: '',
    filters: [
      {
        key: 'candidateGroup',
        // operator: 'has',
        value: 'group-a'
      }
    ],
    color: ''
  },
  {
    id: uuid(),
    name: 'Group B',
    description: '',
    filters: [
      {
        key: 'candidateGroup',
        // operator: 'has',
        value: 'group-a'
      }
    ],
    color: ''
  }
], function(pile) {
  _store.pile[pile.id] = pile;
});

function inPath(expected, given) {
  return given.slice(0, expected.length) === expected;
}

function filter(src, data) {
  var where = {
    exact:  {},
    like:   {},
    before: {},
    after:  {}
  };
  var notFilters = [
    'sortBy',
    'sortOrder',
    'firstResult',
    'maxResults'
  ];

  var likeExp = /Like$/;
  var beforeExp = /Before$/;
  var afterExp = /After$/;

  _.each(data, function(val, key) {
    if (notFilters.indexOf(key) > -1) { return; }

    /* jshint evil: true */
    if (beforeExp.test(key)) {
      where.before[key.split(beforeExp).shift()] = new Date(eval(val) * 1000);
    }
    else if (afterExp.test(key)) {
      where.after[key.split(afterExp).shift()] = new Date(eval(val) * 1000);
    }
    /* jshint evil: false */
    else if (likeExp.test(key)) {
      where.like[key.split(likeExp).shift()] = new RegExp((''+ val).slice(1).slice(0, -1), 'g');
    }
    else {
      where.exact[key] = val;
    }
  });

  var found = _.size(where.exact) ? _.where(src, where.exact) : _.toArray(src);

  found = _.size(where.like) ? _.filter(found, function(item) {
    var keep = true;
    var realKey;
    _.each(where.like, function(search, key) {
      if (!keep) { return; }
      keep = search.test(''+ item[key]);
    });
    return keep;
  }) : found;

  found = _.size(where.before) ? _.filter(found, function(item) {
    var keep = true;
    _.each(where.before, function(val, key) {
      if (!keep) { return; }
      keep = item[key] <= val;
    });
    return keep;
  }) : found;

  found = _.size(where.after) ? _.filter(found, function(item) {
    var keep = true;
    _.each(where.after, function(val, key) {
      if (!keep) { return; }
      keep = item[key] >= val;
    });
    return keep;
  }) : found;

  console.info('found', found.length, where);

  return found;
}

function genericGet(wanted, items, where) {
  var returned;

  if (wanted === 'key') {
    returned = _.findWhere(items, {key: wanted});
  }

  else if (!wanted || wanted === 'count') {
    // var safe = _.clone(where);
    // delete safe.maxResults;
    // delete safe.firstResult;
    // delete safe.sortBy;
    // delete safe.sortOrder;
    returned = filter(items, where);

    // returns an object with "count"
    if (wanted) {
      returned = { count: returned.length };
    }
    // returns an aray of items
    else {
      var offset = parseInt(where.firstResult || 0, 10);
      var limit = offset + parseInt(where.maxResults || 10, 10);
      returned = _.toArray(returned).slice(offset, limit);
    }
  }

  // request by id
  else if (wanted) {
    returned = items[wanted];
  }

  return returned;
}

/**
 * Performs a POST HTTP request
 */
HttpClient.prototype.post = function(path, options) {
  options = options || {};

  var done = options.done || function() {};
  var results;

  var pathParts = path.split('/');
  var resourceName = pathParts.shift();
  console.info('SDK MOCKING: "POST" request on "'+ resourceName +'"', pathParts.join(', '), options.data);

  switch (resourceName) {
    case 'process-definition':
      var action = pathParts[pathParts.length - 1];
      var definition;
      if (pathParts[0] === 'key') {
        definition = _.findWhere(_store.processDefinition, {key: pathParts[1]});
      }
      else {
        definition = _store.processDefinition[pathParts[0]];
      }

      switch (action) {
        case 'submit-form':
          var id = uuid();
          _store.processInstance[id] = {
            id: id,
            definitionId: definition.id,
            businessKey: 'myBusinessKey',
            ended: false,
            suspended: false
          };

          results = _.extend({
            links:[
              {
                method: 'GET',
                href: 'http://localhost:8080/rest-test/process-instance/'+ id,
                rel: 'self'
              }
            ],
          }, _store.processInstance[id]);
          break;
      }
      break;
  }

  // postpone the response to simulate latency
  setTimeout(function() {
    done(null, results);
  }, fixturer.random(300, 700));
};

/**
 * Performs a GET HTTP request
 */
HttpClient.prototype.get = function(path, options) {
  options = options || {};

  var done = options.done || function() {};
  var results;

  var pathParts = path.split('/');
  var resourceName = pathParts.shift();
  console.info('SDK MOCKING: "GET" request on "'+ resourceName +'"', pathParts.join(', '), options.data);

  switch (resourceName) {
    case 'process-definition':
      results = genericGet(pathParts[0], _store.processDefinition, options.data);
      break;

    case 'process-instance':
      results = genericGet(pathParts[0], _store.processInstance, options.data);
      break;

    case 'pile':
      results = genericGet(pathParts[0], _store.pile, options.data);
      break;

    case 'task':
      results = genericGet(pathParts[0], _store.task, options.data);
      break;

    case 'user':
      results = genericGet(pathParts[0], _store.user, options.data);
      break;

    case 'variable-instance':
      results = genericGet(pathParts[0], _store.variable, options.data);
      break;
  }

  // postpone the response to simulate latency
  setTimeout(function() {
    done(null, results);
  }, fixturer.random(300, 700));
};

/**
 * Performs a PUT HTTP request
 */
HttpClient.prototype.put = function(path, options) {
  options = options || {};
  var done = options.done || function() {};
  var results = {};

  done(null, { body: results });
};

/**
 * Performs a DELETE HTTP request
 */
HttpClient.prototype.del = function(data, options) {
  data = data || {};
  options = options || {};
};
module.exports = HttpClient;
<|endoftext|>