<commit_before>import { relative } from 'path';
import { Promise } from 'sander';
import { parse } from 'acorn';
import MagicString from 'magic-string';
import Statement from './Statement';
import analyse from './ast/analyse';
import { has, keys } from './utils/object';
import { sequence } from './utils/promise';
import { isImportDeclaration, isExportDeclaration } from './utils/map-helpers';
import getLocation from './utils/getLocation';
import makeLegalIdentifier from './utils/makeLegalIdentifier';

const emptyArrayPromise = Promise.resolve([]);

export default class Module {
	constructor ({ path, source, bundle }) {
		this.source = source;

		this.bundle = bundle;
		this.path = path;
		this.relativePath = relative( bundle.base, path ).slice( 0, -3 ); // remove .js

		this.magicString = new MagicString( source, {
			filename: path
		});

		this.suggestedNames = {};
		this.comments = [];

		// Try to extract a list of top-level statements/declarations. If
		// the parse fails, attach file info and abort
		try {
			const ast = parse( source, {
				ecmaVersion: 6,
				sourceType: 'module',
				onComment: ( block, text, start, end ) => this.comments.push({ block, text, start, end })
			});

			this.statements = ast.body.map( node => {
				const magicString = this.magicString.snip( node.start, node.end );
				return new Statement( node, magicString, this );
			});
		} catch ( err ) {
			err.file = path;
			throw err;
		}

		this.importDeclarations = this.statements.filter( isImportDeclaration );
		this.exportDeclarations = this.statements.filter( isExportDeclaration );

		this.analyse();
	}

	analyse () {
		// imports and exports, indexed by ID
		this.imports = {};
		this.exports = {};

		this.importDeclarations.forEach( statement => {
			const node = statement.node;
			const source = node.source.value;

			node.specifiers.forEach( specifier => {
				const isDefault = specifier.type === 'ImportDefaultSpecifier';
				const isNamespace = specifier.type === 'ImportNamespaceSpecifier';

				const localName = specifier.local.name;
				const name = isDefault ? 'default' : isNamespace ? '*' : specifier.imported.name;

				if ( has( this.imports, localName ) ) {
					const err = new Error( `Duplicated import '${localName}'` );
					err.file = this.path;
					err.loc = getLocation( this.source, specifier.start );
					throw err;
				}

				this.imports[ localName ] = {
					source,
					name,
					localName
				};
			});
		});

		this.exportDeclarations.forEach( statement => {
			const node = statement.node;
			const source = node.source && node.source.value;

			// export default function foo () {}
			// export default foo;
			// export default 42;
			if ( node.type === 'ExportDefaultDeclaration' ) {
				const isDeclaration = /Declaration$/.test( node.declaration.type );

				this.exports.default = {
					statement,
					name: 'default',
					localName: isDeclaration ? node.declaration.id.name : 'default',
					isDeclaration
				};
			}

			// export { foo, bar, baz }
			// export var foo = 42;
			// export function foo () {}
			else if ( node.type === 'ExportNamedDeclaration' ) {
				if ( node.specifiers.length ) {
					// export { foo, bar, baz }
					node.specifiers.forEach( specifier => {
						const localName = specifier.local.name;
						const exportedName = specifier.exported.name;

						this.exports[ exportedName ] = {
							localName,
							exportedName
						};

						// export { foo } from './foo';
						if ( source ) {
							this.imports[ localName ] = {
								source,
								localName,
								name: exportedName
							};
						}
					});
				}

				else {
					let declaration = node.declaration;

					let name;

					if ( declaration.type === 'VariableDeclaration' ) {
						// export var foo = 42
						name = declaration.declarations[0].id.name;
					} else {
						// export function foo () {}
						name = declaration.id.name;
					}

					this.exports[ name ] = {
						statement,
						localName: name,
						expression: declaration
					};
				}
			}
		});

		analyse( this.magicString, this );

		this.canonicalNames = {};

		this.definitions = {};
		this.definitionPromises = {};
		this.modifications = {};

		this.statements.forEach( statement => {
			Object.keys( statement.defines ).forEach( name => {
				this.definitions[ name ] = statement;
			});

			Object.keys( statement.modifies ).forEach( name => {
				if ( !has( this.modifications, name ) ) {
					this.modifications[ name ] = [];
				}

				this.modifications[ name ].push( statement );
			});
		});
	}

	getCanonicalName ( localName ) {
		if ( has( this.suggestedNames, localName ) ) {
			localName = this.suggestedNames[ localName ];
		}

		if ( !has( this.canonicalNames, localName ) ) {
			let canonicalName;

			if ( has( this.imports, localName ) ) {
				const importDeclaration = this.imports[ localName ];
				const module = importDeclaration.module;

				if ( importDeclaration.name === '*' ) {
					canonicalName = module.suggestedNames[ '*' ];
				} else {
					let exporterLocalName;

					if ( module.isExternal ) {
						exporterLocalName = importDeclaration.name;
					} else {
						const exportDeclaration = module.exports[ importDeclaration.name ];
						exporterLocalName = exportDeclaration.localName;
					}

					canonicalName = module.getCanonicalName( exporterLocalName );
				}
			}

			else {
				canonicalName = localName;
			}

			this.canonicalNames[ localName ] = canonicalName;
		}

		return this.canonicalNames[ localName ];
	}

	define ( name ) {
		// shortcut cycles. TODO this won't work everywhere...
		if ( has( this.definitionPromises, name ) ) {
			return emptyArrayPromise;
		}

		let promise;

		// The definition for this name is in a different module
		if ( has( this.imports, name ) ) {
			const importDeclaration = this.imports[ name ];

			promise = this.bundle.fetchModule( importDeclaration.source, this.path )
				.then( module => {
					importDeclaration.module = module;

					// suggest names. TODO should this apply to non default/* imports?
					if ( importDeclaration.name === 'default' ) {
						// TODO this seems ropey
						const localName = importDeclaration.localName;
						const suggestion = has( this.suggestedNames, localName ) ? this.suggestedNames[ localName ] : localName;
						module.suggestName( 'default', suggestion );
					} else if ( importDeclaration.name === '*' ) {
						const localName = importDeclaration.localName;
						const suggestion = has( this.suggestedNames, localName ) ? this.suggestedNames[ localName ] : localName;
						module.suggestName( '*', suggestion );
						module.suggestName( 'default', `${suggestion}__default` );
					}

					if ( module.isExternal ) {
						if ( importDeclaration.name === 'default' ) {
							module.needsDefault = true;
						} else {
							module.needsNamed = true;
						}

						module.importedByBundle.push( importDeclaration );
						return emptyArrayPromise;
					}

					if ( importDeclaration.name === '*' ) {
						// we need to create an internal namespace
						if ( !~this.bundle.internalNamespaceModules.indexOf( module ) ) {
							this.bundle.internalNamespaceModules.push( module );
						}

						return module.expandAllStatements();
					}

					const exportDeclaration = module.exports[ importDeclaration.name ];

					if ( !exportDeclaration ) {
						throw new Error( `Module ${module.path} does not export ${importDeclaration.name} (imported by ${this.path})` );
					}

					return module.define( exportDeclaration.localName );
				});
		}

		// The definition is in this module
		else if ( name === 'default' && this.exports.default.isDeclaration ) {
			// We have something like `export default foo` - so we just start again,
			// searching for `foo` instead of default
			promise = this.define( this.exports.default.name );
		}

		else {
			let statement;

			if ( name === 'default' ) {
				statement = this.exports.default.statement;
			} else {
				statement = this.definitions[ name ];
			}

			if ( statement && !statement.isIncluded ) {
				promise = statement.expand();
			}
		}

		this.definitionPromises[ name ] = promise || emptyArrayPromise;
		return this.definitionPromises[ name ];
	}

	expandAllStatements ( isEntryModule ) {
		let allStatements = [];

		return sequence( this.statements, statement => {
			// skip already-included statements
			if ( statement.isIncluded ) return;

			// skip import declarations...
			if ( statement.isImportDeclaration ) {
				// ...unless they're empty, in which case assume we're importing them for the side-effects
				// THIS IS NOT FOOLPROOF. Probably need /*rollup: include */ or similar
				if ( !statement.node.specifiers.length ) {
					return this.bundle.fetchModule( statement.node.source.value, this.path )
						.then( module => {
							statement.module = module; // TODO what is this for? what does it do? why not _module?
							return module.expandAllStatements();
						})
						.then( statements => {
							allStatements.push.apply( allStatements, statements );
						});
				}

				return;
			}

			// skip `export { foo, bar, baz }`...
			if ( statement.node.type === 'ExportNamedDeclaration' && statement.node.specifiers.length ) {
				// ...but ensure they are defined, if this is the entry module
				if ( isEntryModule ) {
					return statement.expand().then( statements => {
						allStatements.push.apply( allStatements, statements );
					});
				}

				return;
			}

			// include everything else
			return statement.expand().then( statements => {
				allStatements.push.apply( allStatements, statements );
			});
		}).then( () => {
			return allStatements;
		});
	}

	rename ( name, replacement ) {
		this.canonicalNames[ name ] = replacement;
	}

	suggestName ( exportName, suggestion ) {
		if ( !this.suggestedNames[ exportName ] ) {
			this.suggestedNames[ exportName ] = makeLegalIdentifier( suggestion );
		}
	}
}
<commit_msg>preserve original statement order where possible<commit_after>import { relative } from 'path';
import { Promise } from 'sander';
import { parse } from 'acorn';
import MagicString from 'magic-string';
import Statement from './Statement';
import analyse from './ast/analyse';
import { has, keys } from './utils/object';
import { sequence } from './utils/promise';
import { isImportDeclaration, isExportDeclaration } from './utils/map-helpers';
import getLocation from './utils/getLocation';
import makeLegalIdentifier from './utils/makeLegalIdentifier';

const emptyArrayPromise = Promise.resolve([]);

export default class Module {
	constructor ({ path, source, bundle }) {
		this.source = source;

		this.bundle = bundle;
		this.path = path;
		this.relativePath = relative( bundle.base, path ).slice( 0, -3 ); // remove .js

		this.magicString = new MagicString( source, {
			filename: path
		});

		this.suggestedNames = {};
		this.comments = [];

		// Try to extract a list of top-level statements/declarations. If
		// the parse fails, attach file info and abort
		try {
			const ast = parse( source, {
				ecmaVersion: 6,
				sourceType: 'module',
				onComment: ( block, text, start, end ) => this.comments.push({ block, text, start, end })
			});

			this.statements = ast.body.map( node => {
				const magicString = this.magicString.snip( node.start, node.end );
				return new Statement( node, magicString, this );
			});
		} catch ( err ) {
			err.file = path;
			throw err;
		}

		this.importDeclarations = this.statements.filter( isImportDeclaration );
		this.exportDeclarations = this.statements.filter( isExportDeclaration );

		this.analyse();
	}

	analyse () {
		// imports and exports, indexed by ID
		this.imports = {};
		this.exports = {};

		this.importDeclarations.forEach( statement => {
			const node = statement.node;
			const source = node.source.value;

			node.specifiers.forEach( specifier => {
				const isDefault = specifier.type === 'ImportDefaultSpecifier';
				const isNamespace = specifier.type === 'ImportNamespaceSpecifier';

				const localName = specifier.local.name;
				const name = isDefault ? 'default' : isNamespace ? '*' : specifier.imported.name;

				if ( has( this.imports, localName ) ) {
					const err = new Error( `Duplicated import '${localName}'` );
					err.file = this.path;
					err.loc = getLocation( this.source, specifier.start );
					throw err;
				}

				this.imports[ localName ] = {
					source,
					name,
					localName
				};
			});
		});

		this.exportDeclarations.forEach( statement => {
			const node = statement.node;
			const source = node.source && node.source.value;

			// export default function foo () {}
			// export default foo;
			// export default 42;
			if ( node.type === 'ExportDefaultDeclaration' ) {
				const isDeclaration = /Declaration$/.test( node.declaration.type );

				this.exports.default = {
					statement,
					name: 'default',
					localName: isDeclaration ? node.declaration.id.name : 'default',
					isDeclaration
				};
			}

			// export { foo, bar, baz }
			// export var foo = 42;
			// export function foo () {}
			else if ( node.type === 'ExportNamedDeclaration' ) {
				if ( node.specifiers.length ) {
					// export { foo, bar, baz }
					node.specifiers.forEach( specifier => {
						const localName = specifier.local.name;
						const exportedName = specifier.exported.name;

						this.exports[ exportedName ] = {
							localName,
							exportedName
						};

						// export { foo } from './foo';
						if ( source ) {
							this.imports[ localName ] = {
								source,
								localName,
								name: exportedName
							};
						}
					});
				}

				else {
					let declaration = node.declaration;

					let name;

					if ( declaration.type === 'VariableDeclaration' ) {
						// export var foo = 42
						name = declaration.declarations[0].id.name;
					} else {
						// export function foo () {}
						name = declaration.id.name;
					}

					this.exports[ name ] = {
						statement,
						localName: name,
						expression: declaration
					};
				}
			}
		});

		analyse( this.magicString, this );

		this.canonicalNames = {};

		this.definitions = {};
		this.definitionPromises = {};
		this.modifications = {};

		this.statements.forEach( statement => {
			Object.keys( statement.defines ).forEach( name => {
				this.definitions[ name ] = statement;
			});

			Object.keys( statement.modifies ).forEach( name => {
				if ( !has( this.modifications, name ) ) {
					this.modifications[ name ] = [];
				}

				this.modifications[ name ].push( statement );
			});
		});
	}

	getCanonicalName ( localName ) {
		if ( has( this.suggestedNames, localName ) ) {
			localName = this.suggestedNames[ localName ];
		}

		if ( !has( this.canonicalNames, localName ) ) {
			let canonicalName;

			if ( has( this.imports, localName ) ) {
				const importDeclaration = this.imports[ localName ];
				const module = importDeclaration.module;

				if ( importDeclaration.name === '*' ) {
					canonicalName = module.suggestedNames[ '*' ];
				} else {
					let exporterLocalName;

					if ( module.isExternal ) {
						exporterLocalName = importDeclaration.name;
					} else {
						const exportDeclaration = module.exports[ importDeclaration.name ];
						exporterLocalName = exportDeclaration.localName;
					}

					canonicalName = module.getCanonicalName( exporterLocalName );
				}
			}

			else {
				canonicalName = localName;
			}

			this.canonicalNames[ localName ] = canonicalName;
		}

		return this.canonicalNames[ localName ];
	}

	define ( name ) {
		// shortcut cycles. TODO this won't work everywhere...
		if ( has( this.definitionPromises, name ) ) {
			return emptyArrayPromise;
		}

		let promise;

		// The definition for this name is in a different module
		if ( has( this.imports, name ) ) {
			const importDeclaration = this.imports[ name ];

			promise = this.bundle.fetchModule( importDeclaration.source, this.path )
				.then( module => {
					importDeclaration.module = module;

					// suggest names. TODO should this apply to non default/* imports?
					if ( importDeclaration.name === 'default' ) {
						// TODO this seems ropey
						const localName = importDeclaration.localName;
						const suggestion = has( this.suggestedNames, localName ) ? this.suggestedNames[ localName ] : localName;
						module.suggestName( 'default', suggestion );
					} else if ( importDeclaration.name === '*' ) {
						const localName = importDeclaration.localName;
						const suggestion = has( this.suggestedNames, localName ) ? this.suggestedNames[ localName ] : localName;
						module.suggestName( '*', suggestion );
						module.suggestName( 'default', `${suggestion}__default` );
					}

					if ( module.isExternal ) {
						if ( importDeclaration.name === 'default' ) {
							module.needsDefault = true;
						} else {
							module.needsNamed = true;
						}

						module.importedByBundle.push( importDeclaration );
						return emptyArrayPromise;
					}

					if ( importDeclaration.name === '*' ) {
						// we need to create an internal namespace
						if ( !~this.bundle.internalNamespaceModules.indexOf( module ) ) {
							this.bundle.internalNamespaceModules.push( module );
						}

						return module.expandAllStatements();
					}

					const exportDeclaration = module.exports[ importDeclaration.name ];

					if ( !exportDeclaration ) {
						throw new Error( `Module ${module.path} does not export ${importDeclaration.name} (imported by ${this.path})` );
					}

					return module.define( exportDeclaration.localName );
				});
		}

		// The definition is in this module
		else if ( name === 'default' && this.exports.default.isDeclaration ) {
			// We have something like `export default foo` - so we just start again,
			// searching for `foo` instead of default
			promise = this.define( this.exports.default.name );
		}

		else {
			let statement;

			if ( name === 'default' ) {
				statement = this.exports.default.statement;
			} else {
				statement = this.definitions[ name ];
			}

			if ( statement && !statement.isIncluded ) {
				promise = statement.expand();
			}
		}

		this.definitionPromises[ name ] = promise || emptyArrayPromise;
		return this.definitionPromises[ name ];
	}

	expandAllStatements ( isEntryModule ) {
		let allStatements = [];

		return sequence( this.statements, statement => {
			// A statement may have already been included, in which case we need to
			// curb rollup's enthusiasm and move it down here. It remains to be seen
			// if this approach is bulletproof
			if ( statement.isIncluded ) {
				const index = allStatements.indexOf( statement );
				if ( ~index ) {
					allStatements.splice( index, 1 );
					allStatements.push( statement );
				}

				return;
			}

			// skip import declarations...
			if ( statement.isImportDeclaration ) {
				// ...unless they're empty, in which case assume we're importing them for the side-effects
				// THIS IS NOT FOOLPROOF. Probably need /*rollup: include */ or similar
				if ( !statement.node.specifiers.length ) {
					return this.bundle.fetchModule( statement.node.source.value, this.path )
						.then( module => {
							statement.module = module; // TODO what is this for? what does it do? why not _module?
							return module.expandAllStatements();
						})
						.then( statements => {
							allStatements.push.apply( allStatements, statements );
						});
				}

				return;
			}

			// skip `export { foo, bar, baz }`...
			if ( statement.node.type === 'ExportNamedDeclaration' && statement.node.specifiers.length ) {
				// ...but ensure they are defined, if this is the entry module
				if ( isEntryModule ) {
					return statement.expand().then( statements => {
						allStatements.push.apply( allStatements, statements );
					});
				}

				return;
			}

			// include everything else
			return statement.expand().then( statements => {
				allStatements.push.apply( allStatements, statements );
			});
		}).then( () => {
			return allStatements;
		});
	}

	rename ( name, replacement ) {
		this.canonicalNames[ name ] = replacement;
	}

	suggestName ( exportName, suggestion ) {
		if ( !this.suggestedNames[ exportName ] ) {
			this.suggestedNames[ exportName ] = makeLegalIdentifier( suggestion );
		}
	}
}
<|endoftext|>


<commit_before>'use strict';

const BaseStep = require('./base-step');

module.exports = class VoidStep extends BaseStep {
  constructor(options, action) {
    super(options);
    this.action = action;
  }
  start() {
    this.action && this.action();
    return new Promise(() => {});
  }
};
<commit_msg>Return a resolved promise so promise chains waiting on step and flow resolution can end.<commit_after>'use strict';

const BaseStep = require('./base-step');

module.exports = class VoidStep extends BaseStep {
  constructor(options, action) {
    super(options);
    this.action = action;
  }
  start() {
    this.action && this.action();
    return Promise.resolve();
  }
};
<|endoftext|>


<commit_before>import { relative } from 'path';
import { Promise } from 'sander';
import { parse } from 'acorn';
import MagicString from 'magic-string';
import Statement from './Statement';
import analyse from './ast/analyse';
import { has, keys } from './utils/object';
import { sequence } from './utils/promise';
import { isImportDeclaration, isExportDeclaration } from './utils/map-helpers';
import getLocation from './utils/getLocation';
import makeLegalIdentifier from './utils/makeLegalIdentifier';

const emptyArrayPromise = Promise.resolve([]);

export default class Module {
	constructor ({ path, source, bundle }) {
		this.source = source;

		this.bundle = bundle;
		this.path = path;
		this.relativePath = relative( bundle.base, path ).slice( 0, -3 ); // remove .js

		this.magicString = new MagicString( source, {
			filename: path
		});

		this.suggestedNames = {};
		this.comments = [];

		// Try to extract a list of top-level statements/declarations. If
		// the parse fails, attach file info and abort
		try {
			const ast = parse( source, {
				ecmaVersion: 6,
				sourceType: 'module',
				onComment: ( block, text, start, end ) => this.comments.push({ block, text, start, end })
			});

			this.statements = ast.body.map( node => {
				const magicString = this.magicString.snip( node.start, node.end );
				return new Statement( node, magicString, this );
			});
		} catch ( err ) {
			err.file = path;
			throw err;
		}

		this.importDeclarations = this.statements.filter( isImportDeclaration );
		this.exportDeclarations = this.statements.filter( isExportDeclaration );

		this.analyse();
	}

	analyse () {
		// imports and exports, indexed by ID
		this.imports = {};
		this.exports = {};

		this.importDeclarations.forEach( statement => {
			const node = statement.node;
			const source = node.source.value;

			node.specifiers.forEach( specifier => {
				const isDefault = specifier.type === 'ImportDefaultSpecifier';
				const isNamespace = specifier.type === 'ImportNamespaceSpecifier';

				const localName = specifier.local.name;
				const name = isDefault ? 'default' : isNamespace ? '*' : specifier.imported.name;

				if ( has( this.imports, localName ) ) {
					const err = new Error( `Duplicated import '${localName}'` );
					err.file = this.path;
					err.loc = getLocation( this.source, specifier.start );
					throw err;
				}

				this.imports[ localName ] = {
					source,
					name,
					localName
				};
			});
		});

		this.exportDeclarations.forEach( statement => {
			const node = statement.node;
			const source = node.source && node.source.value;

			// export default function foo () {}
			// export default foo;
			// export default 42;
			if ( node.type === 'ExportDefaultDeclaration' ) {
				const isDeclaration = /Declaration$/.test( node.declaration.type );

				this.exports.default = {
					statement,
					name: 'default',
					localName: isDeclaration ? node.declaration.id.name : 'default',
					isDeclaration
				};
			}

			// export { foo, bar, baz }
			// export var foo = 42;
			// export function foo () {}
			else if ( node.type === 'ExportNamedDeclaration' ) {
				if ( node.specifiers.length ) {
					// export { foo, bar, baz }
					node.specifiers.forEach( specifier => {
						const localName = specifier.local.name;
						const exportedName = specifier.exported.name;

						this.exports[ exportedName ] = {
							localName,
							exportedName
						};

						// export { foo } from './foo';
						if ( source ) {
							this.imports[ localName ] = {
								source,
								localName,
								name: exportedName
							};
						}
					});
				}

				else {
					let declaration = node.declaration;

					let name;

					if ( declaration.type === 'VariableDeclaration' ) {
						// export var foo = 42
						name = declaration.declarations[0].id.name;
					} else {
						// export function foo () {}
						name = declaration.id.name;
					}

					this.exports[ name ] = {
						statement,
						localName: name,
						expression: declaration
					};
				}
			}
		});

		analyse( this.magicString, this );

		this.canonicalNames = {};

		this.definitions = {};
		this.definitionPromises = {};
		this.modifications = {};

		this.statements.forEach( statement => {
			Object.keys( statement.defines ).forEach( name => {
				this.definitions[ name ] = statement;
			});

			Object.keys( statement.modifies ).forEach( name => {
				if ( !has( this.modifications, name ) ) {
					this.modifications[ name ] = [];
				}

				this.modifications[ name ].push( statement );
			});
		});
	}

	getCanonicalName ( localName ) {
		if ( has( this.suggestedNames, localName ) ) {
			localName = this.suggestedNames[ localName ];
		}

		if ( !has( this.canonicalNames, localName ) ) {
			let canonicalName;

			if ( has( this.imports, localName ) ) {
				const importDeclaration = this.imports[ localName ];
				const module = importDeclaration.module;

				if ( importDeclaration.name === '*' ) {
					canonicalName = module.suggestedNames[ '*' ];
				} else {
					let exporterLocalName;

					if ( module.isExternal ) {
						exporterLocalName = importDeclaration.name;
					} else {
						const exportDeclaration = module.exports[ importDeclaration.name ];
						exporterLocalName = exportDeclaration.localName;
					}

					canonicalName = module.getCanonicalName( exporterLocalName );
				}
			}

			else {
				canonicalName = localName;
			}

			this.canonicalNames[ localName ] = canonicalName;
		}

		return this.canonicalNames[ localName ];
	}

	define ( name ) {
		// shortcut cycles. TODO this won't work everywhere...
		if ( has( this.definitionPromises, name ) ) {
			return emptyArrayPromise;
		}

		let promise;

		// The definition for this name is in a different module
		if ( has( this.imports, name ) ) {
			const importDeclaration = this.imports[ name ];

			promise = this.bundle.fetchModule( importDeclaration.source, this.path )
				.then( module => {
					importDeclaration.module = module;

					// suggest names. TODO should this apply to non default/* imports?
					if ( importDeclaration.name === 'default' ) {
						// TODO this seems ropey
						const localName = importDeclaration.localName;
						const suggestion = has( this.suggestedNames, localName ) ? this.suggestedNames[ localName ] : localName;
						module.suggestName( 'default', suggestion );
					} else if ( importDeclaration.name === '*' ) {
						const localName = importDeclaration.localName;
						const suggestion = has( this.suggestedNames, localName ) ? this.suggestedNames[ localName ] : localName;
						module.suggestName( '*', suggestion );
						module.suggestName( 'default', `${suggestion}__default` );
					}

					if ( module.isExternal ) {
						if ( importDeclaration.name === 'default' ) {
							module.needsDefault = true;
						} else {
							module.needsNamed = true;
						}

						module.importedByBundle.push( importDeclaration );
						return emptyArrayPromise;
					}

					if ( importDeclaration.name === '*' ) {
						// we need to create an internal namespace
						if ( !~this.bundle.internalNamespaceModules.indexOf( module ) ) {
							this.bundle.internalNamespaceModules.push( module );
						}

						return module.expandAllStatements();
					}

					const exportDeclaration = module.exports[ importDeclaration.name ];

					if ( !exportDeclaration ) {
						throw new Error( `Module ${module.path} does not export ${importDeclaration.name} (imported by ${this.path})` );
					}

					return module.define( exportDeclaration.localName );
				});
		}

		// The definition is in this module
		else if ( name === 'default' && this.exports.default.isDeclaration ) {
			// We have something like `export default foo` - so we just start again,
			// searching for `foo` instead of default
			promise = this.define( this.exports.default.name );
		}

		else {
			let statement;

			if ( name === 'default' ) {
				// TODO can we use this.definitions[ name ], as below?
				statement = this.exports.default.statement;
			}

			else {
				statement = this.definitions[ name ];
			}

			if ( statement && !statement.isIncluded ) {
				promise = statement.expand();
			}
		}

		this.definitionPromises[ name ] = promise || emptyArrayPromise;
		return this.definitionPromises[ name ];
	}

	expandAllStatements ( isEntryModule ) {
		let allStatements = [];

		return sequence( this.statements, statement => {
			// skip already-included statements
			if ( statement.isIncluded ) return;

			// skip import declarations...
			if ( statement.isImportDeclaration ) {
				// ...unless they're empty, in which case assume we're importing them for the side-effects
				// THIS IS NOT FOOLPROOF. Probably need /*rollup: include */ or similar
				if ( !statement.node.specifiers.length ) {
					return this.bundle.fetchModule( statement.node.source.value, this.path )
						.then( module => {
							statement.module = module; // TODO what is this for? what does it do? why not _module?
							return module.expandAllStatements();
						})
						.then( statements => {
							allStatements.push.apply( allStatements, statements );
						});
				}

				return;
			}

			// skip `export { foo, bar, baz }`...
			if ( statement.node.type === 'ExportNamedDeclaration' && statement.node.specifiers.length ) {
				// ...but ensure they are defined, if this is the entry module
				if ( isEntryModule ) {
					return statement.expand().then( statements => {
						allStatements.push.apply( allStatements, statements );
					});
				}

				return;
			}

			// include everything else
			return statement.expand().then( statements => {
				allStatements.push.apply( allStatements, statements );
			});
		}).then( () => {
			return allStatements;
		});
	}

	rename ( name, replacement ) {
		this.canonicalNames[ name ] = replacement;
	}

	suggestName ( exportName, suggestion ) {
		if ( !this.suggestedNames[ exportName ] ) {
			this.suggestedNames[ exportName ] = makeLegalIdentifier( suggestion );
		}
	}
}
<commit_msg>remove a TODO<commit_after>import { relative } from 'path';
import { Promise } from 'sander';
import { parse } from 'acorn';
import MagicString from 'magic-string';
import Statement from './Statement';
import analyse from './ast/analyse';
import { has, keys } from './utils/object';
import { sequence } from './utils/promise';
import { isImportDeclaration, isExportDeclaration } from './utils/map-helpers';
import getLocation from './utils/getLocation';
import makeLegalIdentifier from './utils/makeLegalIdentifier';

const emptyArrayPromise = Promise.resolve([]);

export default class Module {
	constructor ({ path, source, bundle }) {
		this.source = source;

		this.bundle = bundle;
		this.path = path;
		this.relativePath = relative( bundle.base, path ).slice( 0, -3 ); // remove .js

		this.magicString = new MagicString( source, {
			filename: path
		});

		this.suggestedNames = {};
		this.comments = [];

		// Try to extract a list of top-level statements/declarations. If
		// the parse fails, attach file info and abort
		try {
			const ast = parse( source, {
				ecmaVersion: 6,
				sourceType: 'module',
				onComment: ( block, text, start, end ) => this.comments.push({ block, text, start, end })
			});

			this.statements = ast.body.map( node => {
				const magicString = this.magicString.snip( node.start, node.end );
				return new Statement( node, magicString, this );
			});
		} catch ( err ) {
			err.file = path;
			throw err;
		}

		this.importDeclarations = this.statements.filter( isImportDeclaration );
		this.exportDeclarations = this.statements.filter( isExportDeclaration );

		this.analyse();
	}

	analyse () {
		// imports and exports, indexed by ID
		this.imports = {};
		this.exports = {};

		this.importDeclarations.forEach( statement => {
			const node = statement.node;
			const source = node.source.value;

			node.specifiers.forEach( specifier => {
				const isDefault = specifier.type === 'ImportDefaultSpecifier';
				const isNamespace = specifier.type === 'ImportNamespaceSpecifier';

				const localName = specifier.local.name;
				const name = isDefault ? 'default' : isNamespace ? '*' : specifier.imported.name;

				if ( has( this.imports, localName ) ) {
					const err = new Error( `Duplicated import '${localName}'` );
					err.file = this.path;
					err.loc = getLocation( this.source, specifier.start );
					throw err;
				}

				this.imports[ localName ] = {
					source,
					name,
					localName
				};
			});
		});

		this.exportDeclarations.forEach( statement => {
			const node = statement.node;
			const source = node.source && node.source.value;

			// export default function foo () {}
			// export default foo;
			// export default 42;
			if ( node.type === 'ExportDefaultDeclaration' ) {
				const isDeclaration = /Declaration$/.test( node.declaration.type );

				this.exports.default = {
					statement,
					name: 'default',
					localName: isDeclaration ? node.declaration.id.name : 'default',
					isDeclaration
				};
			}

			// export { foo, bar, baz }
			// export var foo = 42;
			// export function foo () {}
			else if ( node.type === 'ExportNamedDeclaration' ) {
				if ( node.specifiers.length ) {
					// export { foo, bar, baz }
					node.specifiers.forEach( specifier => {
						const localName = specifier.local.name;
						const exportedName = specifier.exported.name;

						this.exports[ exportedName ] = {
							localName,
							exportedName
						};

						// export { foo } from './foo';
						if ( source ) {
							this.imports[ localName ] = {
								source,
								localName,
								name: exportedName
							};
						}
					});
				}

				else {
					let declaration = node.declaration;

					let name;

					if ( declaration.type === 'VariableDeclaration' ) {
						// export var foo = 42
						name = declaration.declarations[0].id.name;
					} else {
						// export function foo () {}
						name = declaration.id.name;
					}

					this.exports[ name ] = {
						statement,
						localName: name,
						expression: declaration
					};
				}
			}
		});

		analyse( this.magicString, this );

		this.canonicalNames = {};

		this.definitions = {};
		this.definitionPromises = {};
		this.modifications = {};

		this.statements.forEach( statement => {
			Object.keys( statement.defines ).forEach( name => {
				this.definitions[ name ] = statement;
			});

			Object.keys( statement.modifies ).forEach( name => {
				if ( !has( this.modifications, name ) ) {
					this.modifications[ name ] = [];
				}

				this.modifications[ name ].push( statement );
			});
		});
	}

	getCanonicalName ( localName ) {
		if ( has( this.suggestedNames, localName ) ) {
			localName = this.suggestedNames[ localName ];
		}

		if ( !has( this.canonicalNames, localName ) ) {
			let canonicalName;

			if ( has( this.imports, localName ) ) {
				const importDeclaration = this.imports[ localName ];
				const module = importDeclaration.module;

				if ( importDeclaration.name === '*' ) {
					canonicalName = module.suggestedNames[ '*' ];
				} else {
					let exporterLocalName;

					if ( module.isExternal ) {
						exporterLocalName = importDeclaration.name;
					} else {
						const exportDeclaration = module.exports[ importDeclaration.name ];
						exporterLocalName = exportDeclaration.localName;
					}

					canonicalName = module.getCanonicalName( exporterLocalName );
				}
			}

			else {
				canonicalName = localName;
			}

			this.canonicalNames[ localName ] = canonicalName;
		}

		return this.canonicalNames[ localName ];
	}

	define ( name ) {
		// shortcut cycles. TODO this won't work everywhere...
		if ( has( this.definitionPromises, name ) ) {
			return emptyArrayPromise;
		}

		let promise;

		// The definition for this name is in a different module
		if ( has( this.imports, name ) ) {
			const importDeclaration = this.imports[ name ];

			promise = this.bundle.fetchModule( importDeclaration.source, this.path )
				.then( module => {
					importDeclaration.module = module;

					// suggest names. TODO should this apply to non default/* imports?
					if ( importDeclaration.name === 'default' ) {
						// TODO this seems ropey
						const localName = importDeclaration.localName;
						const suggestion = has( this.suggestedNames, localName ) ? this.suggestedNames[ localName ] : localName;
						module.suggestName( 'default', suggestion );
					} else if ( importDeclaration.name === '*' ) {
						const localName = importDeclaration.localName;
						const suggestion = has( this.suggestedNames, localName ) ? this.suggestedNames[ localName ] : localName;
						module.suggestName( '*', suggestion );
						module.suggestName( 'default', `${suggestion}__default` );
					}

					if ( module.isExternal ) {
						if ( importDeclaration.name === 'default' ) {
							module.needsDefault = true;
						} else {
							module.needsNamed = true;
						}

						module.importedByBundle.push( importDeclaration );
						return emptyArrayPromise;
					}

					if ( importDeclaration.name === '*' ) {
						// we need to create an internal namespace
						if ( !~this.bundle.internalNamespaceModules.indexOf( module ) ) {
							this.bundle.internalNamespaceModules.push( module );
						}

						return module.expandAllStatements();
					}

					const exportDeclaration = module.exports[ importDeclaration.name ];

					if ( !exportDeclaration ) {
						throw new Error( `Module ${module.path} does not export ${importDeclaration.name} (imported by ${this.path})` );
					}

					return module.define( exportDeclaration.localName );
				});
		}

		// The definition is in this module
		else if ( name === 'default' && this.exports.default.isDeclaration ) {
			// We have something like `export default foo` - so we just start again,
			// searching for `foo` instead of default
			promise = this.define( this.exports.default.name );
		}

		else {
			let statement;

			if ( name === 'default' ) {
				statement = this.exports.default.statement;
			} else {
				statement = this.definitions[ name ];
			}

			if ( statement && !statement.isIncluded ) {
				promise = statement.expand();
			}
		}

		this.definitionPromises[ name ] = promise || emptyArrayPromise;
		return this.definitionPromises[ name ];
	}

	expandAllStatements ( isEntryModule ) {
		let allStatements = [];

		return sequence( this.statements, statement => {
			// skip already-included statements
			if ( statement.isIncluded ) return;

			// skip import declarations...
			if ( statement.isImportDeclaration ) {
				// ...unless they're empty, in which case assume we're importing them for the side-effects
				// THIS IS NOT FOOLPROOF. Probably need /*rollup: include */ or similar
				if ( !statement.node.specifiers.length ) {
					return this.bundle.fetchModule( statement.node.source.value, this.path )
						.then( module => {
							statement.module = module; // TODO what is this for? what does it do? why not _module?
							return module.expandAllStatements();
						})
						.then( statements => {
							allStatements.push.apply( allStatements, statements );
						});
				}

				return;
			}

			// skip `export { foo, bar, baz }`...
			if ( statement.node.type === 'ExportNamedDeclaration' && statement.node.specifiers.length ) {
				// ...but ensure they are defined, if this is the entry module
				if ( isEntryModule ) {
					return statement.expand().then( statements => {
						allStatements.push.apply( allStatements, statements );
					});
				}

				return;
			}

			// include everything else
			return statement.expand().then( statements => {
				allStatements.push.apply( allStatements, statements );
			});
		}).then( () => {
			return allStatements;
		});
	}

	rename ( name, replacement ) {
		this.canonicalNames[ name ] = replacement;
	}

	suggestName ( exportName, suggestion ) {
		if ( !this.suggestedNames[ exportName ] ) {
			this.suggestedNames[ exportName ] = makeLegalIdentifier( suggestion );
		}
	}
}
<|endoftext|>


<commit_before>var geohash = require('ngeohash');
var geolib = require('geolib');

var query = require('./query');
var range = require('./range');

function EmulatedInterface(client) {
    this.client = client;
}

// Native Geo Commands

EmulatedInterface.prototype.geoadd = function(locationName, point, zSetName, callBack) {
    this.client.zadd(zSetName, geohash.encode_int(point.latitude, point.longitude, 52), locationName, callBack);
};

EmulatedInterface.prototype.geoadd_multi = function(locationSet, zSetName, callBack) {
    var argArray = [zSetName];
    var locationName;
    var location;

    for (locationName in locationSet) {
        location = locationSet[locationName];
        argArray.push(geohash.encode_int(location.latitude, location.longitude, 52), locationName);
    }

    this.client.zadd(argArray, callBack);
};

EmulatedInterface.prototype.geodist = function(locationA, locationB, units, zSetName, callBack) {

    var multi = this.client.multi();
    var pointA;
    var pointB;
    var distance;

    multi.zscore(zSetName, locationA);
    multi.zscore(zSetName, locationB);

    multi.exec(function(err, replies) {

        if (err) {
            callBack(err, null);
        } else {

            pointA = geohashDecode(replies[0]);
            pointB = geohashDecode(replies[1]);

            distance = geolib.getDistance(pointA, pointB, 1);
            distance = convertFromMeters(units, distance);

            callBack(null, distance);
        }
    });
};

EmulatedInterface.prototype.geohash = function(member, zSetName, callBack) {

    var point;
    var hash;

    this.client.zscore(zSetName, member, function(err, result) {
        if (err) {
            callBack(err, null);
        } else {
            if (result !== null) {
                point = geohashDecode(result);
                hash = geohash.encode(point.latitude, point.longitude);
            } else {
                hash = null;
            }
            callBack(null, hash);
        }
    });
};

EmulatedInterface.prototype.geohashes = function(members, zSetName, callBack) {

    var locationSet = {};
    var point;
    var i;
    var multi = this.client.multi();

    for (i = 0; i < members.length; i++) {
        multi.zscore(zSetName, members[i]);
    }

    multi.exec(function(err, replies) {

        if (err) {
            callBack(err, null);
        } else {

            for (i = 0; i < replies.length; i++) {
                if (replies[i] !== null) {
                    point = geohashDecode(replies[i]);
                    locationSet[members[i]] = geohash.encode(point.latitude, point.longitude);
                } else {
                    locationSet[members[i]] = null;
                }
            }

            callBack(null, locationSet);
        }
    });
};

EmulatedInterface.prototype.geopos = function(members, zSetName, callBack) {

    var argArray = [zSetName].concat(members);
    var locationSet = {};
    var i;

    this.client.send_command('geopos', argArray, function(err, results) {
        if (err) {
            callBack(err, null);
        } else {
            for (i = 0; i < results.length; i++) {
                if (results[i] !== null) {
                    locationSet[members[i]] = {
                        latitude: results[i][1],
                        longitude: results[i][0]
                    };
                } else {
                    locationSet[members[i]] = null;
                }
            }
            callBack(null, locationSet);
        }
    });
};

EmulatedInterface.prototype.geopos_multi = function(members, zSetName, callBack) {

    var argArray = [zSetName].concat(members);
    var locationSet = {};
    var i;

    this.client.send_command('geopos', argArray, function(err, results) {
        if (err) {
            callBack(err, null);
        } else {
            for (i = 0; i < results.length; i++) {
                if (results[i] !== null) {
                    locationSet[members[i]] = {
                        latitude: results[i][1],
                        longitude: results[i][0]
                    };
                } else {
                    locationSet[members[i]] = null;
                }
            }
            callBack(null, locationSet);
        }
    });
};

EmulatedInterface.prototype.georadius = function(point, radius, options, zSetName, callBack) {
    options.precise = true;
    this.nearby(point, radius, options, zSetName, callBack);
};

EmulatedInterface.prototype.georadiusbymember = function(member, radius, options, zSetName, callBack) {
    options.precise = true;
    this.nearbymember(member, radius, options, zSetName, callBack);
};

EmulatedInterface.prototype.nearby = function(point, distance, options, zSetName, callBack) {

    var ranges;
    var withValues = false;
    var units = options.units || 'm';
    var optionsLength = Object.keys(options).length;

    distance = convertUnitsToMeters(units, distance);

    if ((options.units && optionsLength > 1) || optionsLength > 0) {
        withValues = true;
    }

    ranges = range(point.latitude, point.longitude, distance);

    query(this.client, zSetName, ranges, withValues, function(err, locations) {

        var locationSet = {};

        if (!err) {
            if (withValues === true) {
                locationSet = processLocations(locations, point, distance, options, callBack);
                callBack(null, locationSet);
            }
            callBack(null, locations);
        } else {
            callBack(err, null);
        }
    });
};

EmulatedInterface.prototype.nearbymember = function(locationName, distance, options, zSetName, callBack) {

    var self = this;

    this.geopos([locationName], zSetName, function(err, location) {
        if (!err) {
            self.nearby(location, distance, options, zSetName, callBack);
        } else {
            callBack(err, null);
        }
    });
};

// Native Ordered Set Commands

EmulatedInterface.prototype.del = function(zSetName, callBack) {
    this.client.del(zSetName, callBack);
};

EmulatedInterface.prototype.zrem = function(locations, zSetName, callBack) {
    this.client.zrem(zSetName, locations, callBack);
};

function processLocations(locationSetOriginal, point, queryDistance, options, callBack) {

    var locations = [];

    var units = options.units || 'm';
    var withDistances = options.withDistances;
    var withCoordinates = options.withCoordinates;
    var withHashes = options.withHashes;
    var order = options.order;
    var precise = options.precise;

    var locationName;
    var location;
    var distance;

    if (order) {
        locations = orderResults(locationSetOriginal, point, queryDistance, withDistances, withCoordinates, withHashes, order, precise, units);
    } else {

        for (locationName in locationSetOriginal) {

            location = locationSetOriginal[locationName];
            distance = geolib.getDistance(point, location, 1);

            if (precise !== true || distance <= queryDistance) {

                location.key = locationName;
                location.distance = convertFromMeters(units, distance);

                if (withHashes === true) {
                    location.hash = geohash.encode(location.latitude, location.longitude);
                }

                locations.push(location);
            }
        }
    }

    Object.defineProperty(locations, 'locationSet', {
        get: function() {
            buildLocationSetFromArray(this);
        }
    });

    return locations;
}

function orderResults(locationSetOriginal, point, queryDistance, withDistances, withCoordinates, withHashes, order, precise, units) {

    var orderedLocations = geolib.orderByDistance(point, locationSetOriginal);
    var location;
    var i;

    if (precise) {
        for (i = orderedLocations.length - 1; i > -1; i--) {
            location = orderedLocations[i];
            if (location.distance > queryDistance) {
                orderedLocations = orderedLocations.slice(i);
                break;
            }
        }
    }

    if (withHashes) {
        for (i = 0; i < orderedLocations.length; i++) {
            location = orderedLocations[i];
            location.hash = geohash.encode(location.latitude, location.longitude);
        }
    }

    if (order === 'DESC') {
        orderedLocations = orderedLocations.reverse();
    }

    return orderedLocations;
}

function buildLocationSetFromArray(arr) {

    var locationSet = {};
    var location;
    var i;

    for (i = 0; i < arr.length; i++) {
        location = arr[i];
        locationSet[location.key] = location;
    }

    return locationSet;
}

function convertUnitsToMeters(units, distance) {

    switch (units) {
        case 'km':
            distance = distance * 1000;
            break;
        case 'cm':
            distance = distance / 100;
            break;
        case 'mm':
            distance = distance / 1000;
            break;
        case 'ft':
            distance = distance / 3.28084;
            break;
        case 'mi':
            distance = distance * 1609.34;
            break;
        default:
            break;
    }
    return distance;
}

function convertFromMeters(units, distance) {

    switch (units) {
        case 'km':
            distance = distance / 1000;
            break;
        case 'cm':
            distance = distance * 100;
            break;
        case 'mm':
            distance = distance * 1000;
            break;
        case 'ft':
            distance = distance * 3.28084;
            break;
        case 'mi':
            distance = distance / 1609.34;
            break;
        default:
            break;
    }
    return distance;
}

function geohashDecode(hash) {

    var decoded;
    var latlon;

    if (hash !== null) {

        latlon = geohash.decode_int(hash, 52);

        decoded = {
            latitude: latlon.latitude,
            longitude: latlon.longitude
        };

    } else {

        decoded = {
            latitude: null,
            longitude: null
        };
    }

    return decoded;
}

module.exports = EmulatedInterface;
<commit_msg>Breaking out global methods into helper js.<commit_after>var geohash = require('ngeohash');
var geolib = require('geolib');

var helper = require('./util/helper');

var query = require('./query');
var range = require('./range');

var convertUnitsFromMeters = helper.convertUnitsFromMeters;
var convertUnitsToMeters = helper.convertUnitsToMeters;
var buildObjectFromKeyedArray = helper.buildObjectFromKeyedArray;
var buildObjectFromStringArray = helper.buildObjectFromStringArray;

// emulated interface constructor

function EmulatedInterface(client) {
    this.client = client;
    console.log('GeoRedis using EMULATED interface...');
}

// Native Geo Commands

EmulatedInterface.prototype.geoadd = function(locationName, point, zSetName, callBack) {
    this.client.zadd(zSetName, geohash.encode_int(point.latitude, point.longitude, 52), locationName, callBack);
};

EmulatedInterface.prototype.geoadd_multi = function(locationSet, zSetName, callBack) {
    var argArray = [zSetName];
    var locationName;
    var location;

    for (locationName in locationSet) {
        location = locationSet[locationName];
        argArray.push(geohash.encode_int(location.latitude, location.longitude, 52), locationName);
    }

    this.client.zadd(argArray, callBack);
};

EmulatedInterface.prototype.geodist = function(locationA, locationB, units, zSetName, callBack) {

    var multi = this.client.multi();
    var pointA;
    var pointB;
    var distance;

    multi.zscore(zSetName, locationA);
    multi.zscore(zSetName, locationB);

    multi.exec(function(err, replies) {

        if (err) {
            callBack(err, null);
        } else {

            pointA = geohashDecode(replies[0]);
            pointB = geohashDecode(replies[1]);

            distance = geolib.getDistance(pointA, pointB, 1);
            distance = convertUnitsFromMeters(units, distance);

            callBack(null, distance);
        }
    });
};

EmulatedInterface.prototype.geohash = function(member, zSetName, callBack) {

    var point;
    var hash;

    this.client.zscore(zSetName, member, function(err, result) {
        if (err) {
            callBack(err, null);
        } else {
            if (result !== null) {
                point = geohashDecode(result);
                hash = geohash.encode(point.latitude, point.longitude);
            } else {
                hash = null;
            }
            callBack(null, hash);
        }
    });
};

EmulatedInterface.prototype.geohashes = function(members, zSetName, callBack) {

    var locationSet = {};
    var point;
    var i;
    var multi = this.client.multi();

    for (i = 0; i < members.length; i++) {
        multi.zscore(zSetName, members[i]);
    }

    multi.exec(function(err, replies) {

        if (err) {
            callBack(err, null);
        } else {

            for (i = 0; i < replies.length; i++) {
                if (replies[i] !== null) {
                    point = geohashDecode(replies[i]);
                    locationSet[members[i]] = geohash.encode(point.latitude, point.longitude);
                } else {
                    locationSet[members[i]] = null;
                }
            }

            callBack(null, locationSet);
        }
    });
};

EmulatedInterface.prototype.geopos = function(members, zSetName, callBack) {

    var argArray = [zSetName].concat(members);
    var locationSet = {};
    var i;

    this.client.send_command('geopos', argArray, function(err, results) {
        if (err) {
            callBack(err, null);
        } else {
            for (i = 0; i < results.length; i++) {
                if (results[i] !== null) {
                    locationSet[members[i]] = {
                        latitude: results[i][1],
                        longitude: results[i][0]
                    };
                } else {
                    locationSet[members[i]] = null;
                }
            }
            callBack(null, locationSet);
        }
    });
};

EmulatedInterface.prototype.geopos_multi = function(members, zSetName, callBack) {

    var argArray = [zSetName].concat(members);
    var locationSet = {};
    var i;

    this.client.send_command('geopos', argArray, function(err, results) {
        if (err) {
            callBack(err, null);
        } else {
            for (i = 0; i < results.length; i++) {
                if (results[i] !== null) {
                    locationSet[members[i]] = {
                        latitude: results[i][1],
                        longitude: results[i][0]
                    };
                } else {
                    locationSet[members[i]] = null;
                }
            }
            callBack(null, locationSet);
        }
    });
};

EmulatedInterface.prototype.georadius = function(point, radius, options, zSetName, callBack) {
    options.precise = true;
    this.nearby(point, radius, options, zSetName, callBack);
};

EmulatedInterface.prototype.georadiusbymember = function(member, radius, options, zSetName, callBack) {
    options.precise = true;
    this.nearbymember(member, radius, options, zSetName, callBack);
};

EmulatedInterface.prototype.nearby = function(point, distance, options, zSetName, callBack) {

    var ranges;
    var withValues = false;
    var units = options.units || 'm';
    var optionsLength = Object.keys(options).length;

    distance = convertUnitsToMeters(units, distance);

    ranges = range(point.latitude, point.longitude, distance);

    if ((options.units && optionsLength > 1) || optionsLength > 0) {
        withValues = true;
    }

    query(this.client, zSetName, ranges, withValues, function(err, locations) {

        if (!err) {
            if (withValues === true) {
                locations = processLocations(locations, point, distance, options, callBack);
            } else {
                Object.defineProperty(locations, 'locationSet', {
                    get: function() {
                        buildObjectFromStringArray(this);
                    }
                });
            }

            callBack(null, locations);
        } else {
            callBack(err, null);
        }
    });
};

EmulatedInterface.prototype.nearbymember = function(locationName, distance, options, zSetName, callBack) {

    var self = this;

    this.geopos([locationName], zSetName, function(err, location) {
        if (!err) {
            self.nearby(location, distance, options, zSetName, callBack);
        } else {
            callBack(err, null);
        }
    });
};

// Native Ordered Set Commands

EmulatedInterface.prototype.del = function(zSetName, callBack) {
    this.client.del(zSetName, callBack);
};

EmulatedInterface.prototype.zrem = function(locations, zSetName, callBack) {
    this.client.zrem(zSetName, locations, callBack);
};

function processLocations(locationSetOriginal, point, queryDistance, options, callBack) {

    var locations = [];

    var units = options.units || 'm';
    var withDistances = options.withDistances;
    var withCoordinates = options.withCoordinates;
    var withHashes = options.withHashes;
    var order = options.order;
    var precise = options.precise;

    var locationName;
    var location;
    var distance;

    if (order) {

        locations = orderResults(locationSetOriginal, point, queryDistance, withDistances, withCoordinates, withHashes, order, precise, units);

    } else {

        for (locationName in locationSetOriginal) {

            location = locationSetOriginal[locationName];
            distance = geolib.getDistance(point, location, 1);

            if (precise !== true || distance <= queryDistance) {

                location.key = locationName;
                location.distance = convertUnitsFromMeters(units, distance);

                if (withHashes === true) {
                    location.hash = geohash.encode(location.latitude, location.longitude);
                }

                locations.push(location);
            }
        }
    }

    Object.defineProperty(locations, 'locationSet', {
        get: function() {
            buildObjectFromKeyedArray(this);
        }
    });

    return locations;
}

function orderResults(locationSetOriginal, point, queryDistance, withDistances, withCoordinates, withHashes, order, precise, units) {

    var orderedLocations = geolib.orderByDistance(point, locationSetOriginal);
    var location;
    var i;

    if (precise) {
        for (i = orderedLocations.length - 1; i > -1; i--) {
            location = orderedLocations[i];
            if (location.distance > queryDistance) {
                orderedLocations = orderedLocations.slice(i);
                break;
            }
        }
    }

    if (withHashes) {
        for (i = 0; i < orderedLocations.length; i++) {
            location = orderedLocations[i];
            location.hash = geohash.encode(location.latitude, location.longitude);
        }
    }

    if (order === 'DESC') {
        orderedLocations = orderedLocations.reverse();
    }

    return orderedLocations;
}

function geohashDecode(hash) {

    var decoded;
    var latlon;

    if (hash !== null) {

        latlon = geohash.decode_int(hash, 52);

        decoded = {
            latitude: latlon.latitude,
            longitude: latlon.longitude
        };

    } else {

        decoded = {
            latitude: null,
            longitude: null
        };
    }

    return decoded;
}

module.exports = EmulatedInterface;
<|endoftext|>


<commit_before>import React, { PropTypes } from 'react'
import Drawer from 'material-ui/Drawer';
import MenuItem from 'material-ui/MenuItem';
import { Link } from 'react-router';

class NavBar extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      open: false,
      title:''
    };
  }
  handleToggle(){
    this.setState({open: !this.state.open});
  }
  handleClose(){
    this.setState({open: false});
  }
  componentWillReceiveProps() {
     this.setNavState();
  }
  componentDidMount(){
    this.setNavState();
  }
  setNavState(){
    this.setState({
      title:this.context.router.isActive('/', true) ? 'HOME' :
        this.context.router.isActive('/blog')? 'BLOG' :
        this.context.router.isActive('/account')? 'ACCOUNT' :
        this.context.router.isActive('/about')? 'ABOUT' : 'POST'
    });
  }
  render () {
    let styles={
      title:{
        color:'#fff',
        fontSize:'32px',
        lineHeight:'64px',
        textAlign:'center',
        backgroundColor:'#00BCD4',
        marginBottom:'20px',
        marginTop:'0'
      },
      menu:{
        textAlign:'center'
      },
      link:{
         textDecoration:'none',
         display:'block',
         color:'#333'
      }
    }

    return(

        <Drawer
          docked={false}
          width={256}
          open={this.state.open}
          onRequestChange={(open) => this.setState({open})}
        >

{this.state.title}

            <MenuItem onTouchTap={this.handleClose.bind(this)}>
              <Link to="/" activeStyle={{color: '#E91E63'}} style={styles.link} onlyActiveOnIndex={true}>HOME</Link>
            </MenuItem>
            <MenuItem onTouchTap={this.handleClose.bind(this)}>
              <Link to="/blog" activeStyle={{color: '#E91E63'}} style={styles.link}>BLOG</Link>
            </MenuItem>
            <MenuItem onTouchTap={this.handleClose.bind(this)}>
              <Link to="/account" activeStyle={{color: '#E91E63'}} style={styles.link}>ACCOUNT</Link>
            </MenuItem>
            <MenuItem onTouchTap={this.handleClose.bind(this)}>
              <Link to="/about" activeStyle={{color: '#E91E63'}} style={styles.link}>ABOUT</Link>
            </MenuItem>

        </Drawer>

    )
  }
}
NavBar.contextTypes = {
  router:React.PropTypes.object.isRequired
}
export default NavBar;
<commit_msg>Update NavBar.js<commit_after>import React, { PropTypes } from 'react'
import Drawer from 'material-ui/Drawer';
import MenuItem from 'material-ui/MenuItem';
import { Link } from 'react-router';

class NavBar extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      open: false,
      title:''
    };
  }
  handleToggle(){
    this.setState({open: !this.state.open});
  }
  handleClose(){
    this.setState({open: false});
  }
  componentWillReceiveProps() {
     this.setNavState();
  }
  componentDidMount(){
    this.setNavState();
  }
  setNavState(){
    this.setState({
      title:this.context.router.isActive('/', true) ? 'HOME' :
        this.context.router.isActive('/blog')? 'BLOG' :
        this.context.router.isActive('/account')? 'ACCOUNT' :
        this.context.router.isActive('/about')? 'ABOUT' : 'POST'
    });
  }
  render () {
    let styles={
      title:{
        color:'#fff',
        fontSize:'32px',
        lineHeight:'64px',
        textAlign:'center',
        backgroundColor:'#00BCD4',
        marginBottom:'20px',
        marginTop:'0',
        fontFamilt:'Helvetica Neue,Helvetica,Arial,Microsoft Yahei,Hiragino Sans GB,Heiti SC,WenQuanYi Micro Hei,sans-serif'
      },
      menu:{
        textAlign:'center'
      },
      link:{
         textDecoration:'none',
         display:'block',
         color:'#333'
      }
    }

    return(

        <Drawer
          docked={false}
          width={256}
          open={this.state.open}
          onRequestChange={(open) => this.setState({open})}
        >

{this.state.title}

            <MenuItem onTouchTap={this.handleClose.bind(this)}>
              <Link to="/" activeStyle={{color: '#E91E63'}} style={styles.link} onlyActiveOnIndex={true}>HOME</Link>
            </MenuItem>
            <MenuItem onTouchTap={this.handleClose.bind(this)}>
              <Link to="/blog" activeStyle={{color: '#E91E63'}} style={styles.link}>BLOG</Link>
            </MenuItem>
            <MenuItem onTouchTap={this.handleClose.bind(this)}>
              <Link to="/account" activeStyle={{color: '#E91E63'}} style={styles.link}>ACCOUNT</Link>
            </MenuItem>
            <MenuItem onTouchTap={this.handleClose.bind(this)}>
              <Link to="/about" activeStyle={{color: '#E91E63'}} style={styles.link}>ABOUT</Link>
            </MenuItem>

        </Drawer>

    )
  }
}
NavBar.contextTypes = {
  router:React.PropTypes.object.isRequired
}
export default NavBar;
<|endoftext|>


<commit_before>var AsyncDependenciesBlock = require('webpack/lib/AsyncDependenciesBlock');
var DependenciesBlockVariable = require('webpack/lib/DependenciesBlockVariable');

function HardDependencyBlockPlugin() {}

HardDependencyBlockPlugin.prototype.apply = function(compiler) {
  var mapFreeze, mapThaw;

  compiler.plugin('--hard-source-methods', function(methods) {
    // store = methods.store;
    // fetch = methods.fetch;
    // freeze = methods.freeze;
    // thaw = methods.thaw;
    mapFreeze = methods.mapFreeze;
    mapThaw = methods.mapThaw;
  });

  compiler.plugin('--hard-source-freeze-dependency-variable', function(frozen, variable, extra) {
    return {
      dependencies: mapFreeze('dependency', null, variable.dependencies, extra),
    };
  });

  compiler.plugin('--hard-source-freeze-dependency-block', function(frozen, block, extra) {
    return {
      name: block.chunkName,
      type: block instanceof AsyncDependenciesBlock ?
        'AsyncDependenciesBlock' :
        'DependenciesBlock',
      dependencies: mapFreeze('dependency', null, block.dependencies, extra),
      variables: mapFreeze('dependency-variable', null, block.variables, extra),
      blocks: mapFreeze('dependency-block', null, block.blocks, extra),
    };
  });

  compiler.plugin('--hard-source-thaw-dependency-variable', function(variable, frozen, extra) {
    return new DependenciesBlockVariable(
      frozen.name,
      frozen.expression,
      mapThaw('dependency', null, frozen.dependencies, extra)
    );
  });

  compiler.plugin('--hard-source-thaw-dependency-block', function(block, frozen, extra) {
    if (frozen.type === 'AsyncDependenciesBlock') {
      block = new AsyncDependenciesBlock(frozen.name, extra.parent);
    }
    if (block) {
      var blockExtra = {
        state: extra.state,
        module: extra.module,
        parent: block,
      };
      block.dependencies = mapThaw('dependency', null, frozen.dependencies, blockExtra);
      block.variables = mapThaw('dependency-variable', null, frozen.variables, blockExtra);
      mapThaw('dependency-block', null, frozen.blocks, blockExtra);
    }
    if (frozen.type === 'AsyncDependenciesBlock') {
      extra.parent.addBlock(block);
    }

    return block;
  });
};

module.exports = HardDependencyBlockPlugin;
<commit_msg>Pass the module instead of parent to AsyncDependencyBlock<commit_after>var AsyncDependenciesBlock = require('webpack/lib/AsyncDependenciesBlock');
var DependenciesBlockVariable = require('webpack/lib/DependenciesBlockVariable');

function HardDependencyBlockPlugin() {}

HardDependencyBlockPlugin.prototype.apply = function(compiler) {
  var mapFreeze, mapThaw;

  compiler.plugin('--hard-source-methods', function(methods) {
    // store = methods.store;
    // fetch = methods.fetch;
    // freeze = methods.freeze;
    // thaw = methods.thaw;
    mapFreeze = methods.mapFreeze;
    mapThaw = methods.mapThaw;
  });

  compiler.plugin('--hard-source-freeze-dependency-variable', function(frozen, variable, extra) {
    return {
      dependencies: mapFreeze('dependency', null, variable.dependencies, extra),
    };
  });

  compiler.plugin('--hard-source-freeze-dependency-block', function(frozen, block, extra) {
    return {
      name: block.chunkName,
      type: block instanceof AsyncDependenciesBlock ?
        'AsyncDependenciesBlock' :
        'DependenciesBlock',
      dependencies: mapFreeze('dependency', null, block.dependencies, extra),
      variables: mapFreeze('dependency-variable', null, block.variables, extra),
      blocks: mapFreeze('dependency-block', null, block.blocks, extra),
    };
  });

  compiler.plugin('--hard-source-thaw-dependency-variable', function(variable, frozen, extra) {
    return new DependenciesBlockVariable(
      frozen.name,
      frozen.expression,
      mapThaw('dependency', null, frozen.dependencies, extra)
    );
  });

  compiler.plugin('--hard-source-thaw-dependency-block', function(block, frozen, extra) {
    if (frozen.type === 'AsyncDependenciesBlock') {
      block = new AsyncDependenciesBlock(frozen.name, extra.module);
    }
    if (block) {
      var blockExtra = {
        state: extra.state,
        module: extra.module,
        parent: block,
      };
      block.dependencies = mapThaw('dependency', null, frozen.dependencies, blockExtra);
      block.variables = mapThaw('dependency-variable', null, frozen.variables, blockExtra);
      mapThaw('dependency-block', null, frozen.blocks, blockExtra);
    }
    if (frozen.type === 'AsyncDependenciesBlock') {
      extra.parent.addBlock(block);
    }

    return block;
  });
};

module.exports = HardDependencyBlockPlugin;
<|endoftext|>


<commit_before>import React, { Component, PropTypes } from 'react';
import cx from 'classnames';
import Col from './Col';
import Icon from './Icon';

class Navbar extends Component {
  constructor (props) {
    super(props);
    this.renderSideNav = this.renderSideNav.bind(this);
  }

  componentDidMount () {
    if ($ !== undefined) {
      $('.button-collapse').sideNav();
    }
  }

  renderSideNav () {
    return (

        {this.props.children}

    );
  }

  render () {
    let {brand, className, ...props} = this.props;
    let classes = {
      right: this.props.right,
      'hide-on-med-and-down': true
    };
    let brandClasses = {
      'brand-logo': true,
      right: this.props.left
    };
    return (

          <Col s={12}>
            {brand}

              {this.props.children}

            {this.renderSideNav()}

              <Icon>view_headline</Icon>

          </Col>

    );
  }
}

Navbar.propTypes = {
  brand: PropTypes.node,
  children: PropTypes.node,
  className: PropTypes.string,
  left: PropTypes.bool,
  right: PropTypes.bool
};

export default Navbar;
<commit_msg>Fix console warning on Navbar<commit_after>import React, { Component, PropTypes } from 'react';
import cx from 'classnames';
import Col from './Col';
import Icon from './Icon';

class Navbar extends Component {
  constructor (props) {
    super(props);
    this.renderSideNav = this.renderSideNav.bind(this);
  }

  componentDidMount () {
    if ($ !== undefined) {
      $('.button-collapse').sideNav();
    }
  }

  renderSideNav () {
    return (

        {this.props.children}

    );
  }

  render () {
    const {
      brand,
      className,
      left,
      right,
      ...other
    } = this.props;

    let classes = {
      right: right,
      'hide-on-med-and-down': true
    };

    let brandClasses = {
      'brand-logo': true,
      right: left
    };

    return (

          <Col s={12}>
            {brand}

              {this.props.children}

            {this.renderSideNav()}

              <Icon>view_headline</Icon>

          </Col>

    );
  }
}

Navbar.propTypes = {
  brand: PropTypes.node,
  children: PropTypes.node,
  className: PropTypes.string,
  left: PropTypes.bool,
  right: PropTypes.bool
};

export default Navbar;
<|endoftext|>


<commit_before>/*
 * Return express middleware that measures overall performance.
 */
function factory(parentClient) {
    return function (prefix, options) {
        var client = parentClient.getChildClient(prefix);
        options = options || {};
        var timeByUrl = options.timeByUrl || false
        var onResponeEnd = options.onResponseEnd

        return function (req, res, next) {
            var startTime = new Date();

            // Shadow end request
            var end = res.end;
            res.end = function () {
                end.apply(res, arguments);

                client.timing('response_time', startTime);
                client.increment('response.' + res.statusCode);

                if (timeByUrl && req.route && req.route.path) {
                    var routeName = req.route.path;
                    if (routeName === "/") routeName = "root";
                    // need to get rid of : in route names, remove first /, and replace rest with _
                    routeName = routeName.replace(/:/g, "").replace(/\//, "").replace(/\//g, "_");
                    client.timing('response_time.by_url.' + routeName, startTime);
                };

                if (onResponseEnd) {
                    onResponseEnd(client, startTime, req, res);
                };
            };
            next();
        };
    };
}

module.exports = factory;
<commit_msg>fix unnecasary semi-colons and typo<commit_after>/*
 * Return express middleware that measures overall performance.
 */
function factory(parentClient) {
    return function (prefix, options) {
        var client = parentClient.getChildClient(prefix);
        options = options || {};
        var timeByUrl = options.timeByUrl || false
        var onResponseEnd = options.onResponseEnd

        return function (req, res, next) {
            var startTime = new Date();

            // Shadow end request
            var end = res.end;
            res.end = function () {
                end.apply(res, arguments);

                client.timing('response_time', startTime);
                client.increment('response.' + res.statusCode);

                if (timeByUrl && req.route && req.route.path) {
                    var routeName = req.route.path;
                    if (routeName === "/") routeName = "root";
                    // need to get rid of : in route names, remove first /, and replace rest with _
                    routeName = routeName.replace(/:/g, "").replace(/\//, "").replace(/\//g, "_");
                    client.timing('response_time.by_url.' + routeName, startTime);
                }

                if (onResponseEnd) {
                    onResponseEnd(client, startTime, req, res);
                }
            };
            next();
        };
    };
}

module.exports = factory;
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import PropTypes from 'prop-types';
import cx from 'classnames';
import Col from './Col';
import Icon from './Icon';

class Navbar extends Component {
  constructor(props) {
    super(props);
    this.renderSideNav = this.renderSideNav.bind(this);
  }

  componentDidMount() {
    if (typeof $ !== 'undefined') {
      $('.button-collapse').sideNav(this.props.options);
    }
  }

  renderSideNav() {
    return (

        {this.props.children}

    );
  }

  render() {
    const {
      brand,
      className,
      fixed,
      left,
      right,
      centerLogo,
      href,
      ...other
    } = this.props;

    delete other.options;

    let classes = {
      right: right,
      'hide-on-med-and-down': true
    };

    let brandClasses = {
      'brand-logo': true,
      right: left,
      center: centerLogo
    };

    let content = (

          <Col s={12}>

              {brand}

{this.props.children}

            {this.renderSideNav()}

              <Icon>view_headline</Icon>

          </Col>

    );

    if (fixed) {
      content =
{content}
;
    }

    return content;
  }
}

Navbar.propTypes = {
  brand: PropTypes.node,
  children: PropTypes.node,
  className: PropTypes.string,
  left: PropTypes.bool,
  right: PropTypes.bool,
  centerLogo: PropTypes.bool,
  href: PropTypes.string,
  /**
   * Makes the navbar fixed
   */
  fixed: PropTypes.bool,
  /**
   * Options hash for the sidenav.
   * More info: http://materializecss.com/side-nav.html#options
   */
  options: PropTypes.shape({
    menuWidth: PropTypes.number,
    edge: PropTypes.oneOf(['left', 'right']),
    closeOnClick: PropTypes.bool,
    draggable: PropTypes.bool
  })
};

Navbar.defaultProps = {
  href: '/',
  options: {}
};

export default Navbar;
<commit_msg>Added some comments to the `propTypes`<commit_after>import React, { Component } from 'react';
import PropTypes from 'prop-types';
import cx from 'classnames';
import Col from './Col';
import Icon from './Icon';

class Navbar extends Component {
  constructor(props) {
    super(props);
    this.renderSideNav = this.renderSideNav.bind(this);
  }

  componentDidMount() {
    if (typeof $ !== 'undefined') {
      $('.button-collapse').sideNav(this.props.options);
    }
  }

  renderSideNav() {
    return (

        {this.props.children}

    );
  }

  render() {
    const {
      brand,
      className,
      fixed,
      left,
      right,
      centerLogo,
      href,
      ...other
    } = this.props;

    delete other.options;

    let classes = {
      right: right,
      'hide-on-med-and-down': true
    };

    let brandClasses = {
      'brand-logo': true,
      right: left,
      center: centerLogo
    };

    let content = (

          <Col s={12}>

              {brand}

{this.props.children}

            {this.renderSideNav()}

              <Icon>view_headline</Icon>

          </Col>

    );

    if (fixed) {
      content =
{content}
;
    }

    return content;
  }
}

Navbar.propTypes = {
  brand: PropTypes.node,
  children: PropTypes.node,
  className: PropTypes.string,
  /**
   * Makes the navbar links left aligned
   */
  left: PropTypes.bool,
  /**
   * Makes the navbar links right aligned
   */
  right: PropTypes.bool,
  /**
   * The logo will center itself on medium and down screens.
   * Specifying centerLogo as a prop the logo will always be centered
   */
  centerLogo: PropTypes.bool,
  href: PropTypes.string,
  /**
   * Makes the navbar fixed
   */
  fixed: PropTypes.bool,
  /**
   * Options hash for the sidenav.
   * More info: http://materializecss.com/side-nav.html#options
   */
  options: PropTypes.shape({
    menuWidth: PropTypes.number,
    edge: PropTypes.oneOf(['left', 'right']),
    closeOnClick: PropTypes.bool,
    draggable: PropTypes.bool
  })
};

Navbar.defaultProps = {
  href: '/',
  options: {}
};

export default Navbar;
<|endoftext|>


<commit_before>/*
 * index.js: Top-level include for the utils module.
 *
 * (C) 2010, Nodejitsu Inc.
 *
 */

var jitsu = require('jitsu'),
    util = require('util'),
    eyes = require('eyes'),
    spawn = require('child_process').spawn,
    fs = require('fs'),
    path = require('path');

var utils = exports;

utils.base64 = require('./base64');

//
// ### function snapshotTime (name)
// #### @name {string} Filename for the snapshot
// Returns a formatted date string for the unix time
// in the snapshot filename.
//
utils.snapshotTime = function (name) {
  var time = name.match(/[\w|\-]+-[\w|\-]+-(\d+)/)[1];
  return utils.formatTime(new Date(parseInt(time, 10)));
};

//
// ### function formatTime (obj)
// #### @obj {Date} Date to format
// Returns a formatted date string for `obj` in the format
// YYYY/MM/DD HH:MM:SS
//
utils.formatTime = function (obj) {
  var date = [obj.getFullYear(), obj.getMonth(), obj.getDate()].join('/'),
      time = [obj.getHours(), obj.getMinutes(), obj.getSeconds()].join(':');

  return [date, time].join(' ');
};

//
// ### function readPackage (dir, callback)
// #### @dir {string} Directory to read the package.json from
// #### @callback {function} Continuation to pass control to when complete
// Attempts to read the package.json file out of the specified directory.
//
utils.readPackage = function (dir, callback) {
  var file = path.join(dir, 'package.json');

  fs.readFile(file, function (err, data) {
    if (err) {
      return callback(err);
    }

    try {
      callback(null, JSON.parse(data.toString()));
    }
    catch (ex) {
      callback(ex);
    }
  });
};

//
// ### function createPackage (dir, callback)
// #### @dir {string} Directory to create the package *.tgz file from
// #### @callback {function} Continuation to pass control to when complete
// Creates a *.tgz package file from the specified directory `dir`.
//
utils.createPackage = function (dir, callback) {
  utils.readPackage(dir, function (err, pkg) {
    if (err) {
      return callback(err);
    }

    if (dir.slice(-1) === '/') {
      dir = dir.slice(0, -1);
    }

    var parent = path.dirname(dir),
        base = path.basename(dir),
        tarball = path.join(jitsu.config.settings.tmproot, [jitsu.config.username, pkg.name, Date.now()].join('-') + '.tgz'),
        target = fs.createWriteStream(tarball),
        tarargs = ['-cvf', '-', '--exclude', '.git', '-C', parent, base],
        tar, gzip, errState;

    //
    // TODO (indexzero) Support for `.jitsuignore` files and support for package.json files
    //
    tar = spawn(jitsu.config.settings.tar, tarargs);
    gzip = spawn(jitsu.config.settings.gzipbin, ["--stdout"]);

    //
    // TODO (indexzero) Make this piping more robust
    //
    util.pump(tar.stdout, gzip.stdin);
    util.pump(gzip.stdout, target);

    target.on("close", function (err, ok) {
      if (errState) {
        return;
      }
      else if (err) {
        return callback(errState = err);
      }

      callback(null, pkg, tarball);
    });
  });
};

//
// ### function missingKeys (source, target)
// #### @source {Array} List of keys for the current object
// #### @target {Array} List of keys for the new object
// Returns the complement of the intersection of the two arrays.
//
// e.g. [1,2,3,5], [1,2,3,4,5] => [4]
//
utils.missingKeys = function (source, target) {
  var missing = [];

  source.forEach(function (key) {
    if (target.indexOf(key) === -1) {
      missing.push(key);
    }
  });

  return missing;
};

//
// ### function objectDiff (current, update, level)
// #### @current {Object} Current representation of the object.
// #### @update {Object} Updated representation of the object.
// #### @level {Number} Level in the object we are diffing.
// Returns an incremental diff of the `current` object
// against the updated representation `update`
//
// e.g. { foo: 1, bar: 2 }, { foo: 2, bar: 2 } => { foo: 2 }
//
utils.objectDiff = function (current, update, level) {
  var ckeys = Object.keys(current),
      ukeys = Object.keys(update),
      diff = {};

  //
  // Ignore changes on the first level of the object.
  //
  level = level || 0;
  if (level > 0) {
    utils.missingKeys(ckeys, ukeys).forEach(function (key) {
      diff[key] = undefined;
    });
  }

  ukeys.forEach(function (key) {
    var nested, i;

    if (!current[key]) {
      diff[key] = update[key];
    }
    else if (Array.isArray(update[key])) {
      if (update[key].length !== current[key].length) {
        diff[key] = update[key];
      }
      else {
        for (i = 0; i < update[key]; i += 1) {
          if (current[key].indexOf(update[key][i]) === -1) {
            diff[key] = update[key];
            break;
          }
        }
      }
    }
    else if (typeof update[key] === 'object') {
      if ((nested = utils.objectDiff(current[key], update[key], level + 1))) {
        diff[key] = update[key];
      }
    }
    else {
      if (current[key] !== update[key]) {
        diff[key] = update[key];
      }
    }
  });

  return Object.keys(diff).length > 0 ? diff : null;
};<commit_msg>[api] Dont ignore `.git` folders when packaing application snapshots<commit_after>/*
 * index.js: Top-level include for the utils module.
 *
 * (C) 2010, Nodejitsu Inc.
 *
 */

var jitsu = require('jitsu'),
    util = require('util'),
    eyes = require('eyes'),
    spawn = require('child_process').spawn,
    fs = require('fs'),
    path = require('path');

var utils = exports;

utils.base64 = require('./base64');

//
// ### function snapshotTime (name)
// #### @name {string} Filename for the snapshot
// Returns a formatted date string for the unix time
// in the snapshot filename.
//
utils.snapshotTime = function (name) {
  var time = name.match(/[\w|\-]+-[\w|\-]+-(\d+)/)[1];
  return utils.formatTime(new Date(parseInt(time, 10)));
};

//
// ### function formatTime (obj)
// #### @obj {Date} Date to format
// Returns a formatted date string for `obj` in the format
// YYYY/MM/DD HH:MM:SS
//
utils.formatTime = function (obj) {
  var date = [obj.getFullYear(), obj.getMonth(), obj.getDate()].join('/'),
      time = [obj.getHours(), obj.getMinutes(), obj.getSeconds()].join(':');

  return [date, time].join(' ');
};

//
// ### function readPackage (dir, callback)
// #### @dir {string} Directory to read the package.json from
// #### @callback {function} Continuation to pass control to when complete
// Attempts to read the package.json file out of the specified directory.
//
utils.readPackage = function (dir, callback) {
  var file = path.join(dir, 'package.json');

  fs.readFile(file, function (err, data) {
    if (err) {
      return callback(err);
    }

    try {
      callback(null, JSON.parse(data.toString()));
    }
    catch (ex) {
      callback(ex);
    }
  });
};

//
// ### function createPackage (dir, callback)
// #### @dir {string} Directory to create the package *.tgz file from
// #### @callback {function} Continuation to pass control to when complete
// Creates a *.tgz package file from the specified directory `dir`.
//
utils.createPackage = function (dir, callback) {
  utils.readPackage(dir, function (err, pkg) {
    if (err) {
      return callback(err);
    }

    if (dir.slice(-1) === '/') {
      dir = dir.slice(0, -1);
    }

    var parent = path.dirname(dir),
        base = path.basename(dir),
        tarball = path.join(jitsu.config.settings.tmproot, [jitsu.config.username, pkg.name, Date.now()].join('-') + '.tgz'),
        target = fs.createWriteStream(tarball),
        tarargs = ['-cvf', '-', '-C', parent, base],
        tar, gzip, errState;

    //
    // TODO (indexzero) Support for `.jitsuignore` files and support for package.json files
    //
    tar = spawn(jitsu.config.settings.tar, tarargs);
    gzip = spawn(jitsu.config.settings.gzipbin, ["--stdout"]);

    //
    // TODO (indexzero) Make this piping more robust
    //
    util.pump(tar.stdout, gzip.stdin);
    util.pump(gzip.stdout, target);

    target.on("close", function (err, ok) {
      if (errState) {
        return;
      }
      else if (err) {
        return callback(errState = err);
      }

      callback(null, pkg, tarball);
    });
  });
};

//
// ### function missingKeys (source, target)
// #### @source {Array} List of keys for the current object
// #### @target {Array} List of keys for the new object
// Returns the complement of the intersection of the two arrays.
//
// e.g. [1,2,3,5], [1,2,3,4,5] => [4]
//
utils.missingKeys = function (source, target) {
  var missing = [];

  source.forEach(function (key) {
    if (target.indexOf(key) === -1) {
      missing.push(key);
    }
  });

  return missing;
};

//
// ### function objectDiff (current, update, level)
// #### @current {Object} Current representation of the object.
// #### @update {Object} Updated representation of the object.
// #### @level {Number} Level in the object we are diffing.
// Returns an incremental diff of the `current` object
// against the updated representation `update`
//
// e.g. { foo: 1, bar: 2 }, { foo: 2, bar: 2 } => { foo: 2 }
//
utils.objectDiff = function (current, update, level) {
  var ckeys = Object.keys(current),
      ukeys = Object.keys(update),
      diff = {};

  //
  // Ignore changes on the first level of the object.
  //
  level = level || 0;
  if (level > 0) {
    utils.missingKeys(ckeys, ukeys).forEach(function (key) {
      diff[key] = undefined;
    });
  }

  ukeys.forEach(function (key) {
    var nested, i;

    if (!current[key]) {
      diff[key] = update[key];
    }
    else if (Array.isArray(update[key])) {
      if (update[key].length !== current[key].length) {
        diff[key] = update[key];
      }
      else {
        for (i = 0; i < update[key]; i += 1) {
          if (current[key].indexOf(update[key][i]) === -1) {
            diff[key] = update[key];
            break;
          }
        }
      }
    }
    else if (typeof update[key] === 'object') {
      if ((nested = utils.objectDiff(current[key], update[key], level + 1))) {
        diff[key] = update[key];
      }
    }
    else {
      if (current[key] !== update[key]) {
        diff[key] = update[key];
      }
    }
  });

  return Object.keys(diff).length > 0 ? diff : null;
};<|endoftext|>


<commit_before>var logger = require("./Logger");
var Channel = require('./Channel');
var Collection = require('./Collection');

var ChannelManager = function() {
    this.channels = new Collection();
};

ChannelManager.prototype.handleJoin = function(channelName, conn) {

    var me = this;
    if (!(typeof channelName === "string")) {
        logger.error("channelName", channelName, "is not a string");
        return false;
    }
    if (!(typeof conn === "object")) {
        logger.error("conn", conn, "is not an object");
        return false;
    }
    if (channelName === "") {
        return false;
    }

    var channel;
    if (this.channels.exists(channelName)) {
        channel = this.channels.get(channelName);
    } else {
        channel = new Channel(channelName);
        this.channels.add(channelName, channel);

        channel.on("empty", function() {
            this.channels.remove(channelName);
            logger.info("Channel ", channelName, " is empty");
            channel = undefined;
        }.bind(this));
    }
    channel.join(conn);
};

ChannelManager.prototype.handleLeave = function(channelName, conn) {
    var channel;
    if (this.channels.exists(channelName)) {
        channel = this.channels.get(channelName);
        channel.leave(conn);
    }
};

ChannelManager.prototype.getChannelConnections = function(channel) {
    if (this.channels.has(channel)) {
        logger.debug("Hab den channel");
        return this.channels.get(channel).getConnections();
    } else {
        logger.debug("Nix channel");
        return {};
    }
};

module.exports = ChannelManager;<commit_msg>Fixed comment<commit_after>var logger = require("./Logger");
var Channel = require('./Channel');
var Collection = require('./Collection');

var ChannelManager = function() {
    this.channels = new Collection();
};

ChannelManager.prototype.handleJoin = function(channelName, conn) {

    var me = this;
    if (!(typeof channelName === "string")) {
        logger.error("channelName", channelName, "is not a string");
        return false;
    }
    if (!(typeof conn === "object")) {
        logger.error("conn", conn, "is not an object");
        return false;
    }
    if (channelName === "") {
        return false;
    }

    var channel;
    if (this.channels.exists(channelName)) {
        channel = this.channels.get(channelName);
    } else {
        channel = new Channel(channelName);
        this.channels.add(channelName, channel);

        channel.on("empty", function() {
            this.channels.remove(channelName);
            logger.info("Channel ", channelName, " is empty");
            channel = undefined;
        }.bind(this));
    }
    channel.join(conn);
};

ChannelManager.prototype.handleLeave = function(channelName, conn) {
    var channel;
    if (this.channels.exists(channelName)) {
        channel = this.channels.get(channelName);
        channel.leave(conn);
    }
};

ChannelManager.prototype.getChannelConnections = function(channel) {
    if (this.channels.has(channel)) {
        logger.debug("Channel known");
        return this.channels.get(channel).getConnections();
    } else {
        logger.debug("Channel unknown");
        return {};
    }
};

module.exports = ChannelManager;<|endoftext|>