<commit_before>/* global describe, it, xit, before, beforeEach, after, afterEach */
/* jslint node: true, esnext: true */

"use strict";

const chai = require('chai'),
  assert = chai.assert,
  expect = chai.expect,
  should = chai.should(),
  Service = require('../lib/Service'),
  ServiceConfig = require('../lib/ServiceConfig'),
  ServiceLogger = require('../lib/ServiceLogger'),
  ServiceProviderMixin = require('../lib/ServiceProviderMixin');

class ServiceProvider extends ServiceProviderMixin(Service) {}

class ServiceTest extends Service {
  static get name() {
    return "test";
  }
  get type() {
    return ServiceTest.name;
  }

  get autostart() {
    return true;
  }

  configure(config) {
    delete config.name;
    Object.assign(this, config);
    return this.restartIfRunning();
  }
}

describe('service provider', () => {
  const sp = new ServiceProvider([{
    name: "a"
  }, {
    name: "test",
    key3: 3
  }]);

  describe('initial setup', () => {
    describe('config service', () => {
      it('present', () => assert.equal(sp.services.config.name, 'config'));
      it('preserved initial config', () => assert.deepEqual(Object.keys(sp.services.config.preservedConfigs), [
        'a', 'test'
      ]));
    });

    it('logger service', () => assert.equal(sp.services.logger.name, 'logger'));
    it('can be started', () => sp.start().then(() => assert.equal(sp.state, 'running')));
  });

  describe('without initial config', () => {
    const sp = new ServiceProvider();
    it('present', () => assert.equal(sp.services.config.name, 'config'));
  });

  describe('logging', () => {
    // TODO wait until logger service has fullfilled
    sp.info(`logging`);
  });

  describe('additional service', () => {
    sp.registerService(new ServiceTest({}, sp));
    sp.registerService(new ServiceTest({
      name: "t2"
    }, sp));

    it('test service', () => assert.equal(sp.services.test.name, 'test'));

    describe('configure service', () => {
      it('direct', () => sp.services.test.configure({
        key: "new value"
      }).then(() =>
        assert.equal(sp.services.test.key, "new value")
      ));

      it('send change request over config service', () =>
        sp.services.config.endpoints.config.receive([{
          name: 'config'
        }, {
          name: 'unknown'
        }, {
          name: 'test',
          key1: 4711,
          key2: "2"
        }]).then(() =>
          assert.equal(sp.services.test.key1, 4711)
        )
      );
    });

    it('can be unregistered', () =>
      sp.unregisterService('t2').then(s => assert.isUndefined(sp.services.t2))
    );
  });

  describe('declare service', () => {
    describe('with type', () => {
      setTimeout(() =>
        sp.registerServiceFactory(ServiceTest), 50);

      it('can be declared', () =>
        sp.declareService({
          name: 's2',
          type: 'test',
          key: 1
        }, true).then(
          s => {
            assert.equal(s.name, "s2");
          }
        )
      );

      it('can be declared again', () =>
        sp.declareService({
          name: 's2',
          type: 'test',
          key: 2
        }, true).then(
          s => {
            assert.equal(s.name, "s2");
            assert.equal(s.key, 2);
          }
        )
      );
    });

    describe('without type', () => {
      const sp = new ServiceProvider([{
        name: "a"
      }, {
        name: "test"
      }]);
      setTimeout(() =>
        sp.registerServiceFactory(ServiceTest), 50);

      it('can be declared', () =>
        sp.declareService({
          name: 'test'
        }, true).then(
          s => {
            assert.equal(s.name, "test");
          }
        )
      );
    });
  });
});
<commit_msg>test: increas coverage a bit<commit_after>/* global describe, it, xit, before, beforeEach, after, afterEach */
/* jslint node: true, esnext: true */

"use strict";

const chai = require('chai'),
  assert = chai.assert,
  expect = chai.expect,
  should = chai.should(),
  Service = require('../lib/Service'),
  ServiceConfig = require('../lib/ServiceConfig'),
  ServiceLogger = require('../lib/ServiceLogger'),
  ServiceProviderMixin = require('../lib/ServiceProviderMixin');

class ServiceProvider extends ServiceProviderMixin(Service) {}

class ServiceTest extends Service {
  static get name() {
    return "test";
  }
  get type() {
    return ServiceTest.name;
  }

  get autostart() {
    return true;
  }

  configure(config) {
    delete config.name;
    Object.assign(this, config);
    return this.restartIfRunning();
  }
}

describe('service provider', () => {
  const sp = new ServiceProvider([{
    name: "a"
  }, {
    name: "test",
    key3: 3
  }]);

  describe('initial setup', () => {
    describe('config service', () => {
      it('present', () => assert.equal(sp.services.config.name, 'config'));
      it('preserved initial config', () => assert.deepEqual(Object.keys(sp.services.config.preservedConfigs), [
        'a', 'test'
      ]));
    });

    it('logger service', () => assert.equal(sp.services.logger.name, 'logger'));
    it('can be started', () => sp.start().then(() => assert.equal(sp.state, 'running')));
  });

  describe('without initial config', () => {
    const sp = new ServiceProvider();
    it('present', () => assert.equal(sp.services.config.name, 'config'));
  });

  describe('logging', () => {
    // TODO wait until logger service has fullfilled
    sp.info(`logging`);
  });

  describe('additional service', () => {
    sp.registerService(new ServiceTest({}, sp));
    sp.registerService(new ServiceTest({
      name: "t2"
    }, sp));

    it('test service', () => assert.equal(sp.services.test.name, 'test'));

    describe('configure service', () => {
      it('direct', () => sp.services.test.configure({
        key: "new value"
      }).then(() =>
        assert.equal(sp.services.test.key, "new value")
      ));

      it('send change request over config service', () =>
        sp.services.config.endpoints.config.receive([{
          name: 'config'
        }, {
          name: 'unknown'
        }, {
          name: 'test',
          key1: 4711,
          key2: "2"
        }]).then(() =>
          assert.equal(sp.services.test.key1, 4711)
        )
      );
    });

    it('can be unregistered', () =>
      sp.unregisterService('t2').then(s => assert.isUndefined(sp.services.t2))
    );
  });

  describe('declare service', () => {
    describe('with type', () => {
      setTimeout(() =>
        sp.registerServiceFactory(ServiceTest), 50);

      it('can be declared', () =>
        sp.declareService({
          name: 's2',
          type: 'test',
          key: 1
        }, true).then(
          s => {
            assert.equal(s.name, "s2");
          }
        )
      );

      it('can be declared again', () =>
        sp.declareService({
          name: 's2',
          type: 'test',
          key: 2
        }, true).then(
          s => {
            assert.equal(s.name, "s2");
            assert.equal(s.key, 2);
          }
        )
      );
    });

    describe('without type', () => {
      const sp = new ServiceProvider([{
        name: "a"
      }, {
        name: "test"
      }]);

      sp.declareService({
        name: 'test'
      }, true);

      setTimeout(() =>
        sp.registerServiceFactory(ServiceTest), 50);

      it('can be declared', () =>
        sp.declareService({
          name: 'test'
        }, true).then(
          s => {
            assert.equal(s.name, "test");
          }
        )
      );
    });
  });
});
<|endoftext|>


<commit_before>var ValidationError = require('./errors/ValidationError.js'),
	ranges = require('./ranges.js'),
	unique = require('./unique.js'),
	schemaTools = require('./schema.js');

var finalize = function(data, fn) {
	if (fn) return setImmediate(fn, null, data);
};

var validateObject = function(data, schema, fn, keyPath, options) {

	if (data) {

		if (typeof data !== 'object') {
			return fn(
				new ValidationError(
					keyPath,
					schema._nonFormalizedSchema,
					'type',
					(schema.errors || {}).type || 'Is not of type Object.'
				)
			);
		}

		// Copy schema
		var schemaCopy = {};
		for (var key in schema.schema) schemaCopy[key] = schema.schema[key];

		// Put validated object here
		var validObject = {};

		// Find unknown keys
		for (var key in data) {
			if (schemaCopy[key] === undefined) {
				var wasAllowUnknownKeys = schema.wasAllowUnknownKeys === true || (options || {}).wasAllowUnknownKeys === true;
				switch (schema.unknownKeys || (options || {}).unknownKeys) {
					case 'allow':
						validObject[key] = data[key];
						break;
					case 'remove':
						break;
					default:
						return fn(
							new ValidationError(
								keyPath.concat([key]),
								schema._nonFormalizedSchema,
								(wasAllowUnknownKeys ? 'allowUnknownKeys' : 'unknownKeys'),
								(wasAllowUnknownKeys ? (schema.errors || {}).allowUnknownKeys : (schema.errors || {}).unknownKeys) || 'Unknown key.'
						)
					);
				}
			}
		}

		var validateNextKey = function() {
			for (var key in schemaCopy) break;
			if (!key) return validateCustom(validObject, schema, fn, keyPath, options);

			var keySchema = schemaCopy[key];
			delete schemaCopy[key];

			validateAny(data[key], keySchema, function(err, validData) {
				if (err) return fn(err);
				if (validData !== undefined) validObject[key] = validData;
				validateNextKey();
			}, keyPath.concat([key]), options);

		};

		return validateNextKey();

	}

	return validateCustom(data, schema, fn, keyPath, options);

};

var validateArray = function(data, schema, fn, keyPath, options) {

	if (data) {

		if (!(data instanceof Array)) {
			return fn(
				new ValidationError(
					keyPath,
					schema._nonFormalizedSchema,
					'type',
					(schema.errors || {}).type || 'Is not of type Array.'
				)
			);
		}

		var validArray = [];

		var validateNext = function(idx) {

			if (idx == data.length) {

				if (schema.len && !ranges.testIndex(schema.len, validArray.length)) {
					return fn(
						new ValidationError(
							keyPath,
							schema._nonFormalizedSchema,
							'len',
							(schema.errors || {}).len || 'Array length is not within range of \'' + schema.len + '\'.'
						)
					);
				}

				if (schema.unique) {

					return unique(validArray, function(res) {
						if (res) return validateCustom(validArray, schema, fn, keyPath, options);
						return fn(
							new ValidationError(
								keyPath,
								schema._nonFormalizedSchema,
								'unique',
								(schema.errors || {}).unique || 'Array is not unique.'
							)
						);
					});

				}

				return validateCustom(validArray, schema, fn, keyPath, options);

			}

			validateAny(data[idx], schema.schema, function(err, validData) {
				if (err) return fn(err);
				validArray.push(validData);
				validateNext(idx + 1);
			}, keyPath.concat([ idx.toString() ]), options);

		};

		return validateNext(0);

	}

	return validateCustom(data, schema, fn, keyPath, options);

};

var validateString = function(str, schema, fn, keyPath, options) {

	var validStr = str;

	if (typeof validStr !== 'string') {
		return fn(
			new ValidationError(
				keyPath,
				schema._nonFormalizedSchema,
				'type',
				(schema.errors || {}).type || 'Is not of type String.'
			)
		);
	};

	if (schema.trim == true || (options || {}).trim == true) {
		validStr = validStr.replace(/^\s+|\s+$/g,'');
	}

	if (schema.match) {
		// We are garanteed that match is a RegExp because the finalizer has tested it.
		if (!schema.match.test(validStr)) {
			return fn(
				new ValidationError(
					keyPath,
					schema._nonFormalizedSchema,
					'match',
					(schema.errors || {}).match || 'Does not match expression ' + schema.match.source + '.'
				)
			);
		}
	}

	// Validate enums
	if (schema.enum && schema.enum.indexOf(str) == -1) {
		return fn(
			new ValidationError(
				keyPath,
				schema._nonFormalizedSchema,
				'enum',
				(schema.errors || {}).enum || 'Possible values are ' + schema.enum.map(function(val) {
					return '\"' + val + '\"';
				}).reduce(function(prev, cur, idx, arr) {
					return prev + (idx == arr.length - 1 ? ' and ' : ', ') + cur;
				}) + '.'
			)
		)
	}

	return validateCustom(validStr, schema, fn, keyPath, options);

};

var validateNumber = function(num, schema, fn, keyPath, options) {

	var validNum = num;

	if (typeof validNum === 'string' && /^[0-9]+(?:\.[0-9]+)?$/.test(num)) {
		validNum = parseFloat(validNum);
	} else if (typeof validNum !== 'number') {
		return fn(
			new ValidationError(
				keyPath,
				schema._nonFormalizedSchema,
				'type',
				(schema.errors || {}).type || 'Is not of type Number.'
			)
		);
	}

	if (schema.range) {
		if (!ranges.testIndex(schema.range, validNum)) {
			return fn(
				new ValidationError(
					keyPath,
					schema._nonFormalizedSchema,
					'range',
					(schema.errors || {}).range || 'Not within range of ' + schema.range
				)
			);
		}
	}

	return validateCustom(validNum, schema, fn, keyPath, options);

};

var validateBoolean = function(val, schema, fn, keyPath, options) {

	if (val) {

		if (typeof val === 'string' && /^true|false$/i.test(val)) {
			val = /^true$/i.test(val);
		}

		if (typeof val !== 'boolean') {
			return fn(
				new ValidationError(
					keyPath,
					schema._nonFormalizedSchema,
					'type',
					(schema.errors || {}).type || 'Is not of type Boolean.'
				)
			);
		}

		return validateCustom(val, schema, fn, keyPath, options);

	}

	return validateCustom(val, schema, fn, keyPath, options);

};

var validateDate = function(val, schema, fn, keyPath, options) {

	if (val) {

		if (typeof val === 'string') {
			var date = new Date(val);
			if (!isNaN(date.getDate()))
	 			return validateCustom(date, schema, fn, keyPath, options);

			return fn(
				new ValidationError(
					keyPath,
					schema._nonFormalizedSchema,
					'type',
					(schema.errors || {}).type || 'Is not a valid Date string.'
				)
			);
		}

		if (!(val instanceof Date)) {
			return fn(
				new ValidationError(
					keyPath,
					schema._nonFormalizedSchema,
					'type',
					(schema.errors || {}).type || 'Is not of type Date.'
				)
			);
		}

		return validateCustom(val, schema, fn, keyPath, options);

	}

	return validateCustom(val, schema, fn, keyPath, options);

};

var validateCustom = function(data, schema, fn, keyPath, options) {

	// All other validators always end with calling the custom validator.
	// - therefore just finalize if there is none.
	if (schema.custom === undefined) return finalize(data, fn);

	var result = data;

	(function validateNext(idx) {
		if (idx === schema.custom.length) return finalize(result, fn);

		var custom = schema.custom[idx];

		// Synchronous functions only have two parameters
		if (custom.length < 3) {
			var res;
			try {
				res = custom(result, schema);
			} catch (err) {
				return fn(ValidationError.fromError(keyPath, schema._nonFormalizedSchema, 'custom', err));
			}
			if (typeof res !== 'undefined') result = res;
			return validateNext(idx + 1);
		}

		// Asynchronous function
		return custom(result, schema, function(err, validData) {
			if (err) return fn(ValidationError.fromError(keyPath,	schema._nonFormalizedSchema, 'custom', err));
			result = validData;
			validateNext(idx + 1);
		});

	})(0);

}

var validateAny = function(data, schema, fn, keyPath, options) {

	// If schema is not yet formalized - formalize it and come back.
	if (schema._nonFormalizedSchema === undefined) {
		return schemaTools.formalize(schema, function(formalizedSchema) {
			return validateAny(data, formalizedSchema, fn, keyPath, options);
		});
	}

	if (typeof data === 'undefined' || data === null) {
		if (data === null) {
			if (schema.allowNull === true || (options || {}).allowNull === true) {
				return validateCustom(data, schema, fn, keyPath, options);
			}
			return fn(
				new ValidationError(
					keyPath,
					schema._nonFormalizedSchema,
					'allowNull',
					(schema.errors || {}).allowNull || 'Cannot be null.'
				)
			);
		}
		if (typeof schema.default !== 'undefined') {
			if (typeof schema.default === 'function') {
				// If function has no arguments it is assumed sync.
				if (schema.default.length == 0) {
					return validateCustom(schema.default(), schema, fn, keyPath, options);
				} else {
					return schema.default(function(defaultValue) {
						validateCustom(defaultValue, schema, fn, keyPath, options);
					});
				}
			} else {
				// Else just apply default value.
				return validateCustom(schema.default, schema, fn, keyPath, options);
			}
		}
		if (schema.required === true || (options || {}).required === true) {
			return fn(
				new ValidationError(
					keyPath,
					schema._nonFormalizedSchema,
					'required',
					 (schema.errors || {}).required || 'Data is required.'
				 )
			 );
		} else {
			return validateCustom(data, schema, fn, keyPath, options);
		}
	}

	if (schema.type === undefined) return validateCustom(data, schema, fn, keyPath, options);
	if ('Object' == schema.type.name) return validateObject(data, schema, fn, keyPath, options);
	if ('Array' == schema.type.name) return validateArray(data, schema, fn, keyPath, options);
	if ('String' == schema.type.name) return validateString(data, schema, fn, keyPath, options);
	if ('Number' == schema.type.name) return validateNumber(data, schema, fn, keyPath, options);
	if ('Boolean' == schema.type.name) return validateBoolean(data, schema, fn, keyPath, options);
	if ('Date' == schema.type.name) return validateDate(data, schema, fn, keyPath, options);

	// This error should have been eliminated by the finalizer.
	throw new Error('Cannot validate schema of type ' + schema.type.name + '.');

};

module.exports = function(data, schema, fn, keyPath, options) {

	if (typeof schema === 'undefined') throw new Error('Missing parameter schema.');
	if (typeof fn === 'undefined') throw new Error('Missing parameter fn.');

	if (options === undefined && typeof keyPath == 'object' && keyPath.constructor.name == 'Object') {
		options = keyPath;
		keyPath = undefined;
	}

	// For backwards compatibility to before version 1.0.3
  // we change the allowUnknownKeys to unknownKeys
	if (typeof (options || {}).allowUnknownKeys === 'boolean') {
		if (!process.env['ISVALID_SILENCE']) {
      console.error('isvalid: DEPRECATED: Validator allowUnknownKeys has been deprecated in favour of unknownKeys as of version 1.0.4. See README for more info.')
    }
		options.unknownKeys = (options.allowUnknownKeys ? 'allow' : 'deny');
		options.wasAllowUnknownKeys = true;
		delete options.allowUnknownKeys;
	}

	keyPath = keyPath || [];

	return validateAny(data, schema, fn, keyPath, options);

};
<commit_msg>Moved the finalizer to the function that uses it.<commit_after>var ValidationError = require('./errors/ValidationError.js'),
	ranges = require('./ranges.js'),
	unique = require('./unique.js'),
	schemaTools = require('./schema.js');

var validateObject = function(data, schema, fn, keyPath, options) {

	if (data) {

		if (typeof data !== 'object') {
			return fn(
				new ValidationError(
					keyPath,
					schema._nonFormalizedSchema,
					'type',
					(schema.errors || {}).type || 'Is not of type Object.'
				)
			);
		}

		// Copy schema
		var schemaCopy = {};
		for (var key in schema.schema) schemaCopy[key] = schema.schema[key];

		// Put validated object here
		var validObject = {};

		// Find unknown keys
		for (var key in data) {
			if (schemaCopy[key] === undefined) {
				var wasAllowUnknownKeys = schema.wasAllowUnknownKeys === true || (options || {}).wasAllowUnknownKeys === true;
				switch (schema.unknownKeys || (options || {}).unknownKeys) {
					case 'allow':
						validObject[key] = data[key];
						break;
					case 'remove':
						break;
					default:
						return fn(
							new ValidationError(
								keyPath.concat([key]),
								schema._nonFormalizedSchema,
								(wasAllowUnknownKeys ? 'allowUnknownKeys' : 'unknownKeys'),
								(wasAllowUnknownKeys ? (schema.errors || {}).allowUnknownKeys : (schema.errors || {}).unknownKeys) || 'Unknown key.'
						)
					);
				}
			}
		}

		var validateNextKey = function() {
			for (var key in schemaCopy) break;
			if (!key) return validateCustom(validObject, schema, fn, keyPath, options);

			var keySchema = schemaCopy[key];
			delete schemaCopy[key];

			validateAny(data[key], keySchema, function(err, validData) {
				if (err) return fn(err);
				if (validData !== undefined) validObject[key] = validData;
				validateNextKey();
			}, keyPath.concat([key]), options);

		};

		return validateNextKey();

	}

	return validateCustom(data, schema, fn, keyPath, options);

};

var validateArray = function(data, schema, fn, keyPath, options) {

	if (data) {

		if (!(data instanceof Array)) {
			return fn(
				new ValidationError(
					keyPath,
					schema._nonFormalizedSchema,
					'type',
					(schema.errors || {}).type || 'Is not of type Array.'
				)
			);
		}

		var validArray = [];

		var validateNext = function(idx) {

			if (idx == data.length) {

				if (schema.len && !ranges.testIndex(schema.len, validArray.length)) {
					return fn(
						new ValidationError(
							keyPath,
							schema._nonFormalizedSchema,
							'len',
							(schema.errors || {}).len || 'Array length is not within range of \'' + schema.len + '\'.'
						)
					);
				}

				if (schema.unique) {

					return unique(validArray, function(res) {
						if (res) return validateCustom(validArray, schema, fn, keyPath, options);
						return fn(
							new ValidationError(
								keyPath,
								schema._nonFormalizedSchema,
								'unique',
								(schema.errors || {}).unique || 'Array is not unique.'
							)
						);
					});

				}

				return validateCustom(validArray, schema, fn, keyPath, options);

			}

			validateAny(data[idx], schema.schema, function(err, validData) {
				if (err) return fn(err);
				validArray.push(validData);
				validateNext(idx + 1);
			}, keyPath.concat([ idx.toString() ]), options);

		};

		return validateNext(0);

	}

	return validateCustom(data, schema, fn, keyPath, options);

};

var validateString = function(str, schema, fn, keyPath, options) {

	var validStr = str;

	if (typeof validStr !== 'string') {
		return fn(
			new ValidationError(
				keyPath,
				schema._nonFormalizedSchema,
				'type',
				(schema.errors || {}).type || 'Is not of type String.'
			)
		);
	};

	if (schema.trim == true || (options || {}).trim == true) {
		validStr = validStr.replace(/^\s+|\s+$/g,'');
	}

	if (schema.match) {
		// We are garanteed that match is a RegExp because the formalizer has tested it.
		if (!schema.match.test(validStr)) {
			return fn(
				new ValidationError(
					keyPath,
					schema._nonFormalizedSchema,
					'match',
					(schema.errors || {}).match || 'Does not match expression ' + schema.match.source + '.'
				)
			);
		}
	}

	// Validate enums
	if (schema.enum && schema.enum.indexOf(str) == -1) {
		return fn(
			new ValidationError(
				keyPath,
				schema._nonFormalizedSchema,
				'enum',
				(schema.errors || {}).enum || 'Possible values are ' + schema.enum.map(function(val) {
					return '\"' + val + '\"';
				}).reduce(function(prev, cur, idx, arr) {
					return prev + (idx == arr.length - 1 ? ' and ' : ', ') + cur;
				}) + '.'
			)
		)
	}

	return validateCustom(validStr, schema, fn, keyPath, options);

};

var validateNumber = function(num, schema, fn, keyPath, options) {

	var validNum = num;

	if (typeof validNum === 'string' && /^[0-9]+(?:\.[0-9]+)?$/.test(num)) {
		validNum = parseFloat(validNum);
	} else if (typeof validNum !== 'number') {
		return fn(
			new ValidationError(
				keyPath,
				schema._nonFormalizedSchema,
				'type',
				(schema.errors || {}).type || 'Is not of type Number.'
			)
		);
	}

	if (schema.range) {
		if (!ranges.testIndex(schema.range, validNum)) {
			return fn(
				new ValidationError(
					keyPath,
					schema._nonFormalizedSchema,
					'range',
					(schema.errors || {}).range || 'Not within range of ' + schema.range
				)
			);
		}
	}

	return validateCustom(validNum, schema, fn, keyPath, options);

};

var validateBoolean = function(val, schema, fn, keyPath, options) {

	if (val) {

		if (typeof val === 'string' && /^true|false$/i.test(val)) {
			val = /^true$/i.test(val);
		}

		if (typeof val !== 'boolean') {
			return fn(
				new ValidationError(
					keyPath,
					schema._nonFormalizedSchema,
					'type',
					(schema.errors || {}).type || 'Is not of type Boolean.'
				)
			);
		}

		return validateCustom(val, schema, fn, keyPath, options);

	}

	return validateCustom(val, schema, fn, keyPath, options);

};

var validateDate = function(val, schema, fn, keyPath, options) {

	if (val) {

		if (typeof val === 'string') {
			var date = new Date(val);
			if (!isNaN(date.getDate()))
	 			return validateCustom(date, schema, fn, keyPath, options);

			return fn(
				new ValidationError(
					keyPath,
					schema._nonFormalizedSchema,
					'type',
					(schema.errors || {}).type || 'Is not a valid Date string.'
				)
			);
		}

		if (!(val instanceof Date)) {
			return fn(
				new ValidationError(
					keyPath,
					schema._nonFormalizedSchema,
					'type',
					(schema.errors || {}).type || 'Is not of type Date.'
				)
			);
		}

		return validateCustom(val, schema, fn, keyPath, options);

	}

	return validateCustom(val, schema, fn, keyPath, options);

};

var validateCustom = function(data, schema, fn, keyPath, options) {

	var finalize = function(data, fn) {
		if (fn) return setImmediate(fn, null, data);
	};

	// All other validators always end with calling the custom validator.
	// - therefore just finalize if there is none.
	if (schema.custom === undefined) return finalize(data, fn);

	var result = data;

	(function validateNext(idx) {
		if (idx === schema.custom.length) return finalize(result, fn);

		var custom = schema.custom[idx];

		// Synchronous functions only have two parameters
		if (custom.length < 3) {
			var res;
			try {
				res = custom(result, schema);
			} catch (err) {
				return fn(ValidationError.fromError(keyPath, schema._nonFormalizedSchema, 'custom', err));
			}
			if (typeof res !== 'undefined') result = res;
			return validateNext(idx + 1);
		}

		// Asynchronous function
		return custom(result, schema, function(err, validData) {
			if (err) return fn(ValidationError.fromError(keyPath,	schema._nonFormalizedSchema, 'custom', err));
			result = validData;
			validateNext(idx + 1);
		});

	})(0);

}

var validateAny = function(data, schema, fn, keyPath, options) {

	// If schema is not yet formalized - formalize it and come back.
	if (schema._nonFormalizedSchema === undefined) {
		return schemaTools.formalize(schema, function(formalizedSchema) {
			return validateAny(data, formalizedSchema, fn, keyPath, options);
		});
	}

	if (typeof data === 'undefined' || data === null) {
		if (data === null) {
			if (schema.allowNull === true || (options || {}).allowNull === true) {
				return validateCustom(data, schema, fn, keyPath, options);
			}
			return fn(
				new ValidationError(
					keyPath,
					schema._nonFormalizedSchema,
					'allowNull',
					(schema.errors || {}).allowNull || 'Cannot be null.'
				)
			);
		}
		if (typeof schema.default !== 'undefined') {
			if (typeof schema.default === 'function') {
				// If function has no arguments it is assumed sync.
				if (schema.default.length == 0) {
					return validateCustom(schema.default(), schema, fn, keyPath, options);
				} else {
					return schema.default(function(defaultValue) {
						validateCustom(defaultValue, schema, fn, keyPath, options);
					});
				}
			} else {
				// Else just apply default value.
				return validateCustom(schema.default, schema, fn, keyPath, options);
			}
		}
		if (schema.required === true || (options || {}).required === true) {
			return fn(
				new ValidationError(
					keyPath,
					schema._nonFormalizedSchema,
					'required',
					 (schema.errors || {}).required || 'Data is required.'
				 )
			 );
		} else {
			return validateCustom(data, schema, fn, keyPath, options);
		}
	}

	if (schema.type === undefined) return validateCustom(data, schema, fn, keyPath, options);
	if ('Object' == schema.type.name) return validateObject(data, schema, fn, keyPath, options);
	if ('Array' == schema.type.name) return validateArray(data, schema, fn, keyPath, options);
	if ('String' == schema.type.name) return validateString(data, schema, fn, keyPath, options);
	if ('Number' == schema.type.name) return validateNumber(data, schema, fn, keyPath, options);
	if ('Boolean' == schema.type.name) return validateBoolean(data, schema, fn, keyPath, options);
	if ('Date' == schema.type.name) return validateDate(data, schema, fn, keyPath, options);

	// This error should have been eliminated by the formalizer.
	throw new Error('Cannot validate schema of type ' + schema.type.name + '.');

};

module.exports = function(data, schema, fn, keyPath, options) {

	if (typeof schema === 'undefined') throw new Error('Missing parameter schema.');
	if (typeof fn === 'undefined') throw new Error('Missing parameter fn.');

	if (options === undefined && typeof keyPath == 'object' && keyPath.constructor.name == 'Object') {
		options = keyPath;
		keyPath = undefined;
	}

	// For backwards compatibility to before version 1.0.3
  // we change the allowUnknownKeys to unknownKeys
	if (typeof (options || {}).allowUnknownKeys === 'boolean') {
		if (!process.env['ISVALID_SILENCE']) {
      console.error('isvalid: DEPRECATED: Validator allowUnknownKeys has been deprecated in favour of unknownKeys as of version 1.0.4. See README for more info.')
    }
		options.unknownKeys = (options.allowUnknownKeys ? 'allow' : 'deny');
		options.wasAllowUnknownKeys = true;
		delete options.allowUnknownKeys;
	}

	keyPath = keyPath || [];

	return validateAny(data, schema, fn, keyPath, options);

};
<|endoftext|>


<commit_before>(function() {
  var Validator = require('jsonschema').Validator;

  var v = new Validator();

  // Address, to be embedded on Person
  var addressSchema = {
   "id": "/SimpleAddress",
   "type": "object",
   "properties": {
     "lines": {
       "type": "array",
       "items": {"type": "string"}
     },
     "zip": {"type": "string"},
     "city": {"type": "string"},
     "country": {"type": "string", "required": true}
   }
  };

  // Person
  var schema = {
   "id": "/SimplePerson",
   "type": "object",
   "properties": {
     "name": {"type": "string"},
     "address": {"$ref": "/SimpleAddress"},
     "votes": {"type": "integer", "minimum": 1}
   }
  };

  var p = {
   "name": "Barack Obama",
   "address": {
     "lines": [ "1600 Pennsylvania Avenue Northwest" ],
     "zip": "DC 20500",
     "city": "Washington",
     "country": "USA"
   },
   "votes": 50
  };

  v.addSchema(addressSchema, '/SimpleAddress');

  console.log(v.validate(p, schema).errors);
})();<commit_msg>remove validate example<commit_after><|endoftext|>


<commit_before>'use strict';
var jsonlint = require('jsonlint-lines-primitives');
var reference = require('./reference');
var parseCSSColor = require('csscolorparser').parseCSSColor;

module.exports = {};
module.exports.value = value;

['v2','v3','v4'].forEach(function(version) {
    var ref = reference(version);
    // Create validator for version
    module.exports[version] = validator(ref);
    // Create validators for each container ('style', 'bucket', etc.)
    for (var container in ref) {
        if (typeof ref[container] !== 'object') continue;
        if (ref[container].type && typeof ref[container].type !== 'object') continue;
        module.exports[version][container] = validateContainer(ref, container);
    }
});

// Generates a validation function for a container object.
function validateContainer(ref, container) {
    return function (property, val, line) {
        var errors = [];
        var spec = ref[container][property];
        if (!spec) {
            errors.push({
                message: container + ' property unrecognized: ' + property,
                line: line
            });
        } else {
            value(property, val, {}, ref, spec, errors);
        }
        return errors;
    };
}

function validator(ref) {
    var validate = function(str) {
        var style, errors = [];
        try {
            style = jsonlint.parse(str.toString());
        } catch(e) {
            var match = e.message.match(/line (\d+)/),
                lineNumber = 0;
            if (match) lineNumber = parseInt(match[1], 10);
            return [{
                line: lineNumber - 1,
                message: e.message,
                error: e
            }];
        }

        style = jsonlint.parse(str.toString());
        value('', style, style.constants||{}, ref, ref.$root, errors, null);

        return errors;
    };
    return validate;
}

// Main recursive validation function. Tracks:
//
// - key: string representing location of validation in style tree. Used only
//   for more informative error reporting. Example: `styles.default.road`
// - val: current value from style being evaluated. May be anything from a
//   high level object that needs to be descended into deeper or a simple
//   scalar value.
// - constants: object of constants for the style to resolve constant values.
// - ref: full reference object. Used if any point in validation refers to
//   a type defined at the root-level of the reference object.
// - spec: current spec being evaluated. Tracks val.
// - errors: array of errors passed by reference.
// - constline: line number of a constant, if it has already been substituted.
//
// Returns true if the `val` passed (and any children recursed into) pass
// the validation defined by `spec`. Returns false if validation fails.
// Validation errors will be pushed onto the errors array.
function value(key, val, constants, ref, spec, errors, constline) {
    var pass = true;

    var line = val.__line__;

    val = unbundle(val);

    // Resolve constants.
    var constline;
    if (typeof val === 'string' && constants[val] !== undefined) constline = constants[val].__line__, val = constants[val];

    val = unbundle(val);

    // Spec specifies a non-native type (bucket, style, etc.)
    if (spec.type && ref[spec.type]) {
        return value(key, val, constants, ref, ref[spec.type], errors);
    // Spec specifies a type, but val must be an array of those (layers only atm).
    } else if (spec.type === 'array' && spec.value) {
        if (Array.isArray(val)) {
            if (spec.length && val.length !== spec.length) {
                errors.push({
                    message: key + ': array length ' + spec.length + ' expected, length ' + val.length + ' found',
                    line: constline ? constline : line
                });
                return false;
            }
            for (var i = 0; i < val.length; i++) {
                var valspec = ref[spec.value]||spec.value;
                if (typeof valspec === 'string' || typeof valspec === 'number') {
                    if (spec.function && Array.isArray(val[i])) {
                        pass = value(key, val[i], constants, ref, ref.function, errors, constline);
                    } else {
                        pass = validateNative(key + '[' + i + ']', val[i], valspec, errors, constline) && pass;
                    }
                } else {
                    pass = value(key + '[' + i + ']', val[i], constants, ref, valspec, errors, constline) && pass;
                }
            }
            return pass;
        } else {
            errors.push({
                message: key + ': array expected, ' + typeof val + ' found',
                line: constline ? constline : line
            });
            return false;
        }
    // Spec specifies an array of specs val may match.
    } else if (Array.isArray(spec)) {
        var sub = [];
        var valid = spec.some(function(s) {
            var spec = typeof s === 'string' ? (ref[s] || s) : s;
            if (typeof spec === 'string') {
                return validateNative(key, val, spec, sub, constline);
            } else {
                return value(key, val, constants, ref, spec, sub, constline);
            }
        });
        if (!valid) sub.forEach(function(err) { errors.push(err); });
        return valid;
    // Val is a function.
    } else if (spec.function && typeof val === 'object' && !Array.isArray(val)) {
        return value(key, val, constants, ref, ref.function, errors, constline);
    // Val must be one of enumerated values.
    } else if (spec.type === 'enum') {
        return validateEnum(key, val, spec.values, errors, constline);
    // Val must match a type.
    } else if (spec.type && typeof spec.type === 'string') {
        return validateNative(key, val, spec.type, errors, constline);
    // No type defined: spec is a container. Val must be an object
    // and must have keys matching the container object definition.
    } else {
        for (var k in val) {
            var childkey = (key ? key + '.' : key) + k;
            var speckey = k.split('.')[0]; // treat 'style.*' as 'style'
            var def = spec[speckey] || spec['*'] || undefined;
            if (!def) {
                errors.push({
                    message: spec.__name__ + ' property unrecognized: ' + k,
                    line: constline ? constline : line
                });
                pass = false;
                continue;
            }
            pass = value(childkey, val[k], constants, ref, def, errors, constline) && pass;
        }
        for (var l in spec) {
            if (spec[l].required && spec[l]['default'] === undefined && val[l] === undefined) {
                errors.push({
                    message: spec.__name__ + ' property ' + l + ' required',
                    line: constline ? constline : line
                });
                pass = false;
            }
        }
        return pass;
    }
}

function unbundle(_) {
    if (_ instanceof Number ||
        _ instanceof String ||
        _ instanceof Boolean) {
        return _.valueOf();
    } else {
        return _;
    }
}

function validateNative(key, val, spec, errors, constline) {
    if (spec === '*') return true;

    var line = val.__line__;

    val = unbundle(val);

    var type = Array.isArray(val) ? 'array' : typeof val;

    if (spec === 'color') {
        if (type !== 'string') {
            errors.push({
                message: key + ': ' + spec + ' expected, ' + type + ' found',
                line: constline ? constline : line
            });
            return false;
        } else if (parseCSSColor(val) === null) {
            errors.push({
                message: key + ': ' + spec + ' expected, ' + val + ' found',
                line: constline ? constline : line
            });
            return false;
        } else {
            return true;
        }
    }

    if (type !== spec) {
        errors.push({
            message: key + ': ' + spec + ' expected, ' + (typeof val) + ' found',
            line: val ? (constline ? constline : line) : null
        });
        return false;
    } else {
        return true;
    }
}

function validateEnum(key, val, spec, errors, constline) {
    var line = val.__line__;
    val = unbundle(val);
    if (spec.indexOf(val) === -1) {
        errors.push({
            message: key + ': expected one of [' + spec.join(', ') + '], ' + val + ' found',
            line: constline ? constline : line
        });
        return false;
    } else {
        return true;
    }
}
<commit_msg>fix node test failures<commit_after>'use strict';
var jsonlint = require('jsonlint-lines-primitives');
var reference = require('./reference');
var parseCSSColor = require('csscolorparser').parseCSSColor;

module.exports = {};
module.exports.value = value;

['v2','v3','v4'].forEach(function(version) {
    var ref = reference(version);
    // Create validator for version
    module.exports[version] = validator(ref);
    // Create validators for each container ('style', 'bucket', etc.)
    for (var container in ref) {
        if (typeof ref[container] !== 'object') continue;
        if (ref[container].type && typeof ref[container].type !== 'object') continue;
        module.exports[version][container] = validateContainer(ref, container);
    }
});

// Generates a validation function for a container object.
function validateContainer(ref, container) {
    return function (property, val, line) {
        var errors = [];
        var spec = ref[container][property];
        if (!spec) {
            errors.push({
                message: container + ' property unrecognized: ' + property,
                line: line
            });
        } else {
            value(property, val, {}, ref, spec, errors);
        }
        return errors;
    };
}

function validator(ref) {
    var validate = function(str) {
        var style, errors = [];
        try {
            style = jsonlint.parse(str.toString());
        } catch(e) {
            var match = e.message.match(/line (\d+)/),
                lineNumber = 0;
            if (match) lineNumber = parseInt(match[1], 10);
            return [{
                line: lineNumber - 1,
                message: e.message,
                error: e
            }];
        }

        style = jsonlint.parse(str.toString());
        var constline;
        value('', style, style.constants||{}, ref, ref.$root, errors, constline);

        return errors;
    };
    return validate;
}

// Main recursive validation function. Tracks:
//
// - key: string representing location of validation in style tree. Used only
//   for more informative error reporting. Example: `styles.default.road`
// - val: current value from style being evaluated. May be anything from a
//   high level object that needs to be descended into deeper or a simple
//   scalar value.
// - constants: object of constants for the style to resolve constant values.
// - ref: full reference object. Used if any point in validation refers to
//   a type defined at the root-level of the reference object.
// - spec: current spec being evaluated. Tracks val.
// - errors: array of errors passed by reference.
// - constline: line number of a constant, if it has already been substituted.
//
// Returns true if the `val` passed (and any children recursed into) pass
// the validation defined by `spec`. Returns false if validation fails.
// Validation errors will be pushed onto the errors array.
function value(key, val, constants, ref, spec, errors, constline) {
    var pass = true;

    var line = val.__line__;

    val = unbundle(val);

    // Resolve constants.
    if (typeof val === 'string' && constants[val] !== undefined) {
        constline = constants[val].__line__;
        val = constants[val];
    }

    val = unbundle(val);

    // Spec specifies a non-native type (bucket, style, etc.)
    if (spec.type && ref[spec.type]) {
        return value(key, val, constants, ref, ref[spec.type], errors);
    // Spec specifies a type, but val must be an array of those (layers only atm).
    } else if (spec.type === 'array' && spec.value) {
        if (Array.isArray(val)) {
            if (spec.length && val.length !== spec.length) {
                errors.push({
                    message: key + ': array length ' + spec.length + ' expected, length ' + val.length + ' found',
                    line: constline ? constline : line
                });
                return false;
            }
            for (var i = 0; i < val.length; i++) {
                var valspec = ref[spec.value]||spec.value;
                if (typeof valspec === 'string' || typeof valspec === 'number') {
                    if (spec.function && Array.isArray(val[i])) {
                        pass = value(key, val[i], constants, ref, ref.function, errors, constline);
                    } else {
                        pass = validateNative(key + '[' + i + ']', val[i], valspec, errors, constline) && pass;
                    }
                } else {
                    pass = value(key + '[' + i + ']', val[i], constants, ref, valspec, errors, constline) && pass;
                }
            }
            return pass;
        } else {
            errors.push({
                message: key + ': array expected, ' + typeof val + ' found',
                line: constline ? constline : line
            });
            return false;
        }
    // Spec specifies an array of specs val may match.
    } else if (Array.isArray(spec)) {
        var sub = [];
        var valid = spec.some(function(s) {
            var spec = typeof s === 'string' ? (ref[s] || s) : s;
            if (typeof spec === 'string') {
                return validateNative(key, val, spec, sub, constline);
            } else {
                return value(key, val, constants, ref, spec, sub, constline);
            }
        });
        if (!valid) sub.forEach(function(err) { errors.push(err); });
        return valid;
    // Val is a function.
    } else if (spec.function && typeof val === 'object' && !Array.isArray(val)) {
        return value(key, val, constants, ref, ref.function, errors, constline);
    // Val must be one of enumerated values.
    } else if (spec.type === 'enum') {
        return validateEnum(key, val, spec.values, errors, constline);
    // Val must match a type.
    } else if (spec.type && typeof spec.type === 'string') {
        return validateNative(key, val, spec.type, errors, constline);
    // No type defined: spec is a container. Val must be an object
    // and must have keys matching the container object definition.
    } else {
        for (var k in val) {
            var childkey = (key ? key + '.' : key) + k;
            var speckey = k.split('.')[0]; // treat 'style.*' as 'style'
            var def = spec[speckey] || spec['*'] || undefined;
            if (!def) {
                errors.push({
                    message: spec.__name__ + ' property unrecognized: ' + k,
                    line: constline ? constline : line
                });
                pass = false;
                continue;
            }
            pass = value(childkey, val[k], constants, ref, def, errors, constline) && pass;
        }
        for (var l in spec) {
            if (spec[l].required && spec[l]['default'] === undefined && val[l] === undefined) {
                errors.push({
                    message: spec.__name__ + ' property ' + l + ' required',
                    line: constline ? constline : line
                });
                pass = false;
            }
        }
        return pass;
    }
}

function unbundle(_) {
    if (_ instanceof Number ||
        _ instanceof String ||
        _ instanceof Boolean) {
        return _.valueOf();
    } else {
        return _;
    }
}

function validateNative(key, val, spec, errors, constline) {
    if (spec === '*') return true;

    var line = val.__line__;

    val = unbundle(val);

    var type = Array.isArray(val) ? 'array' : typeof val;

    if (spec === 'color') {
        if (type !== 'string') {
            errors.push({
                message: key + ': ' + spec + ' expected, ' + type + ' found',
                line: constline ? constline : line
            });
            return false;
        } else if (parseCSSColor(val) === null) {
            errors.push({
                message: key + ': ' + spec + ' expected, ' + val + ' found',
                line: constline ? constline : line
            });
            return false;
        } else {
            return true;
        }
    }

    if (type !== spec) {
        errors.push({
            message: key + ': ' + spec + ' expected, ' + (typeof val) + ' found',
            line: val ? (constline ? constline : line) : null
        });
        return false;
    } else {
        return true;
    }
}

function validateEnum(key, val, spec, errors, constline) {
    var line = val.__line__;
    val = unbundle(val);
    if (spec.indexOf(val) === -1) {
        errors.push({
            message: key + ': expected one of [' + spec.join(', ') + '], ' + val + ' found',
            line: constline ? constline : line
        });
        return false;
    } else {
        return true;
    }
}
<|endoftext|>


<commit_before>/*jslint indent: 2, nomen: true, maxlen: 100, white: true, plusplus: true, unparam: true */
/*global exports, appCollection*/

////////////////////////////////////////////////////////////////////////////////
/// @brief functionality to expose API documentation for Foxx apps
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2010-2013 triagens GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
///     http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is triAGENS GmbH, Cologne, Germany
///
/// @author Michael Hackstein
/// @author Copyright 2011-2013, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////

exports.Swagger = function () {
  "use strict";

  var db = require("internal").db,
    _aal = db._collection("_aal"),
    _ = require("underscore"),
    foxx_manager = require("org/arangodb/foxx/manager");

  // Define the functionality to receive the documentation.
  // And transform it into swagger format.

  // Get the overview of all installed foxxes.
  this.list = function(basePath) {
    var result = {},
    apis = [],
    res = _aal.byExample({"type": "mount"});
    result.swaggerVersion = "1.1";
    result.basePath = basePath;
    result.apis = apis;
    while (res.hasNext()) {
      var m = res.next().mount;
      if (m === "/aardvark") {

      } else {
        apis.push({
          path: m
        });
      }
    }
    return result;
  },

  this.listOne = function(basePath, key) {
    var result = {},
      res;

    if (key.substr(0, 4) === "dev:") {
      res = "/dev/" + key.split(":")[2];
    }
    else {
      res = _aal.document(key).mount;
    }

    result.swaggerVersion = "1.1";
    result.basePath = basePath;

    result.apis = [
      {path: res}
    ];

    return result;
  },

  // Get details of one specific installed foxx.
  this.show = function(mount) {
      var result = {},
      apis = [],
      pathes,
      regex = /(:)([^\/]*)/,
      i,
      url,
      api,
      ops,
      app,
      list = foxx_manager.appRoutes().concat(foxx_manager.developmentRoutes());

      _.each(list, function(r) {
        var ac = r.appContext;
        if (ac.mount === mount) {
          app = r;
          return;
        }
      });

      result.swaggerVersion = "1.1";
      result.basePath = app.urlPrefix;
      result.apis = apis;
      result.models = app.models;
      pathes = app.routes;

      for (i in pathes) {
        if (pathes[i].url.methods !== undefined) {
          url = pathes[i].url.match;
          api = {};
          ops = [];
          url = url.replace(regex, "{$2}");
          api.path = url;
          ops.push(pathes[i].docs);
          api.operations = ops;
          apis.push(api);
        }
      }

      return result;
    }
};
<commit_msg>Fix for more than one path param in the swagger docs<commit_after>/*jslint indent: 2, nomen: true, maxlen: 100, white: true, plusplus: true, unparam: true */
/*global exports, appCollection*/

////////////////////////////////////////////////////////////////////////////////
/// @brief functionality to expose API documentation for Foxx apps
///
/// @file
///
/// DISCLAIMER
///
/// Copyright 2010-2013 triagens GmbH, Cologne, Germany
///
/// Licensed under the Apache License, Version 2.0 (the "License");
/// you may not use this file except in compliance with the License.
/// You may obtain a copy of the License at
///
///     http://www.apache.org/licenses/LICENSE-2.0
///
/// Unless required by applicable law or agreed to in writing, software
/// distributed under the License is distributed on an "AS IS" BASIS,
/// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
/// See the License for the specific language governing permissions and
/// limitations under the License.
///
/// Copyright holder is triAGENS GmbH, Cologne, Germany
///
/// @author Michael Hackstein
/// @author Copyright 2011-2013, triAGENS GmbH, Cologne, Germany
////////////////////////////////////////////////////////////////////////////////

exports.Swagger = function () {
  "use strict";

  var db = require("internal").db,
    _aal = db._collection("_aal"),
    _ = require("underscore"),
    foxx_manager = require("org/arangodb/foxx/manager");

  // Define the functionality to receive the documentation.
  // And transform it into swagger format.

  // Get the overview of all installed foxxes.
  this.list = function(basePath) {
    var result = {},
    apis = [],
    res = _aal.byExample({"type": "mount"});
    result.swaggerVersion = "1.1";
    result.basePath = basePath;
    result.apis = apis;
    while (res.hasNext()) {
      var m = res.next().mount;
      if (m === "/aardvark") {

      } else {
        apis.push({
          path: m
        });
      }
    }
    return result;
  },

  this.listOne = function(basePath, key) {
    var result = {},
      res;

    if (key.substr(0, 4) === "dev:") {
      res = "/dev/" + key.split(":")[2];
    }
    else {
      res = _aal.document(key).mount;
    }

    result.swaggerVersion = "1.1";
    result.basePath = basePath;

    result.apis = [
      {path: res}
    ];

    return result;
  },

  // Get details of one specific installed foxx.
  this.show = function(mount) {
      var result = {},
      apis = [],
      pathes,
      regex = /(:)([^\/]*)/g,
      i,
      url,
      api,
      ops,
      app,
      list = foxx_manager.appRoutes().concat(foxx_manager.developmentRoutes());

      _.each(list, function(r) {
        var ac = r.appContext;
        if (ac.mount === mount) {
          app = r;
          return;
        }
      });

      result.swaggerVersion = "1.1";
      result.basePath = app.urlPrefix;
      result.apis = apis;
      result.models = app.models;
      pathes = app.routes;

      for (i in pathes) {
        if (pathes[i].url.methods !== undefined) {
          url = pathes[i].url.match;
          api = {};
          ops = [];
          url = url.replace(regex, "{$2}");
          api.path = url;
          ops.push(pathes[i].docs);
          api.operations = ops;
          apis.push(api);
        }
      }

      return result;
    }
};
<|endoftext|>


<commit_before>function Virastar(text, options) {
    if(!(this instanceof Virastar))
        return new Virastar(text, options);
    text = text || {};
    if (typeof text == "object")
        this._init(text);
    else if (typeof text == "string") {
        this._init(options || {});
        return this.cleanup(text);
    }
    return this;
}

Virastar.prototype._init = function(options) {
    var opts = {};
    opts.fix_dashes = options.fix_dashes || true;
    opts.fix_three_dots = options.fix_three_dots || true;
    opts.fix_english_quotes = options.fix_english_quotes || true;
    opts.fix_hamzeh = options.fix_hamzeh || true;
    opts.cleanup_zwnj = options.cleanup_zwnj || true;
    opts.fix_spacing_for_braces_and_quotes = options.fix_spacing_for_braces_and_quotes || true;
    opts.fix_arabic_numbers = options.fix_arabic_numbers || true;
    opts.fix_english_numbers = options.fix_english_numbers || true;
    opts.fix_misc_non_persian_chars = options.fix_misc_non_persian_chars || true;
    opts.fix_perfix_spacing = options.fix_perfix_spacing || true;
    opts.fix_suffix_spacing = options.fix_suffix_spacing || true;
    opts.aggresive = options.aggresive || true;
    opts.cleanup_kashidas = options.cleanup_kashidas || true;
    opts.cleanup_extra_marks = options.cleanup_extra_marks || true;
    opts.cleanup_spacing = options.cleanup_spacing || true;
    opts.cleanup_begin_and_end = options.cleanup_begin_and_end || true;
    //preserve URIs
    opts.preserve_URIS = options.preserve_URIS || true;
    this.opts = opts;
}

Virastar.prototype.cleanup = function(text) {
    var opts = this.opts;

    // removing URIs bringing them back at the end of process
    if (opts.preserve_URIS) {

		var URI_regex=new RegExp( "([A-Za-z][A-Za-z0-9+\\-.]*):(?:(//)(?:((?:[A-Za-z0-9\\-._~!$&'()*+,;=:]|%[0-9A-Fa-f]{2})*)@)?((?:\\[(?:(?:(?:(?:[0-9A-Fa-f]{1,4}:){6}|::(?:[0-9A-Fa-f]{1,4}:){5}|(?:[0-9A-Fa-f]{1,4})?::(?:[0-9A-Fa-f]{1,4}:){4}|(?:(?:[0-9A-Fa-f]{1,4}:){0,1}[0-9A-Fa-f]{1,4})?::(?:[0-9A-Fa-f]{1,4}:){3}|(?:(?:[0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})?::(?:[0-9A-Fa-f]{1,4}:){2}|(?:(?:[0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})?::[0-9A-Fa-f]{1,4}:|(?:(?:[0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})?::)(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))|(?:(?:[0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})?::[0-9A-Fa-f]{1,4}|(?:(?:[0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})?::)|[Vv][0-9A-Fa-f]+\\.[A-Za-z0-9\\-._~!$&'()*+,;=:]+)\\]|(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)|(?:[A-Za-z0-9\\-._~!$&'()*+,;=]|%[0-9A-Fa-f]{2})*))(?::([0-9]*))?((?:/(?:[A-Za-z0-9\\-._~!$&'()*+,;=:@]|%[0-9A-Fa-f]{2})*)*)|/((?:(?:[A-Za-z0-9\\-._~!$&'()*+,;=:@]|%[0-9A-Fa-f]{2})+(?:/(?:[A-Za-z0-9\\-._~!$&'()*+,;=:@]|%[0-9A-Fa-f]{2})*)*)?)|((?:[A-Za-z0-9\\-._~!$&'()*+,;=:@]|%[0-9A-Fa-f]{2})+(?:/(?:[A-Za-z0-9\\-._~!$&'()*+,;=:@]|%[0-9A-Fa-f]{2})*)*)|)(?:\\?((?:[A-Za-z0-9\\-._~!$&'()*+,;=:@/?]|%[0-9A-Fa-f]{2})*))?(?:\\#((?:[A-Za-z0-9\\-._~!$&'()*+,;=:@/?]|%[0-9A-Fa-f]{2})*))?","g" );
		// URI_regex by https://github.com/jhermsmeier/uri.regex

        var URIs = [];

        text = text.replace(URI_regex, function(URI) {
            URIs.push(URI);
            return "__URI__PRESERVER__";
        })

    }

    // replace double dash to ndash and triple dash to mdash
    if (opts.fix_dashes) {
        text = text.replace(/-{3}/g, '—')
        text = text.replace(/-{2}/g, '–')
    }

    // replace three dots with ellipsis
    if (opts.fix_three_dots)
        text = text.replace(/\s*\.{3,}/g, '…');

    // replace English quotes with their Persian equivalent
    if (opts.fix_english_quotes)
        text = text.replace(/(["'`]+)(.+?)(\1)/g, '«$2»');

    // should convert ه ی to ه
    if (opts.fix_hamzeh)
        text = text.replace(/(\S)(ه[\s]+[یي])(\s)/g, '$1\u0647\u0654$3');

    // remove unnecessary zwnj char that are succeeded/preceded by a space
    if (opts.cleanup_zwnj)
        text = text.replace(/\s+|\s+/g, ' ');

    var charBatchReplace = function(text, chars, Rchars) {
        var charsA = chars.split("");
        var RcharsA = Rchars.split("");
        for (var i in charsA)
            text = text.replace(new RegExp(charsA[i],'g'), RcharsA[i])
        return text;
    }

    // character replacement
    persian_numbers = "۱۲۳۴۵۶۷۸۹۰"
    arabic_numbers = "١٢٣٤٥٦٧٨٩٠"
    english_numbers = "1234567890"
    bad_chars = ",;كي%"
    good_chars = "،؛کی٪"
    if (opts.fix_english_numbers)
        text = charBatchReplace(text, english_numbers, persian_numbers);
    if (opts.fix_arabic_numbers)
        text = charBatchReplace(text, arabic_numbers, persian_numbers);
    if (opts.fix_misc_non_persian_chars)
        text = charBatchReplace(text, bad_chars, good_chars);

    // should not replace exnglish chars in english phrases
    text = text.replace(/([a-zA-Z\-_]{2,}[۰-۹]+|[۰-۹]+[a-zA-Z\-_]{2,})/g, function(match) {
        return charBatchReplace(match, persian_numbers, english_numbers);

    });

    // put zwnj between word and prefix (mi* nemi*)
    // there's a possible bug here: می and نمی could be separate nouns and not prefix
    if (opts.fix_perfix_spacing)
        text = text.replace(/\s+(ن?می)\s+/g, '\u200C\u0020$1\u200C')

    // put zwnj between word and suffix (*tar *tarin *ha *haye)
    // there's a possible bug here: های and تر could be separate nouns and not suffix
    if (opts.fix_suffix_spacing)
    text = text.replace(/\s+(تر(ی(ن)?)?|ها(ی)?)\s+/g, '\u200C$1\u0020') // in case you can not read it: \s+(tar(i(n)?)?|ha(ye)?)\s+

    // -- Aggressive Editing ------------------------------------------
    if (opts.aggresive) {

        // replace more than one ! or ? mark with just one
        if (opts.cleanup_extra_marks) {
            text = text.replace(/(!){2,}/g, '$1')
            text = text.replace(/(\u061F){2,}/g, '$1') //\u061F ==؟
        }

        // should remove all kashida
        if (opts.cleanup_kashidas)
            text = text.replace(/ـ+/g, "")

    }
    // ----------------------------------------------------------------

    // should fix outside and inside spacing for () [] {}  “” «»
    if (opts.fix_spacing_for_braces_and_quotes) {
        text = text.replace(/[ \t]*(\()\s*([^)]+?)\s*?(\))[ \t]*/g, ' $1$2$3 ')
        text = text.replace(/[ \t]*(\[)\s*([^\]]+?)\s*?(\])[ \t]*/g, ' $1$2$3 ')
        text = text.replace(/[ \t]*(\{)\s*([^}]+?)\s*?(\})[ \t]*/g, ' $1$2$3 ')
        text = text.replace(/[ \t]*(“)\s*([^”]+?)\s*?(”)[ \t]*/g, ' $1$2$3 ')
        text = text.replace(/[ \t]*(«)\s*([^»]+?)\s*?(»)[ \t]*/g, ' $1$2$3 ')
    }

    // : ; , . ! ? and their persian equivalents should have one space after and no space before
    if (opts.fix_spacing_for_braces_and_quotes) {
        text = text.replace(/[ \t]*([:;,؛،.؟!]{1})[ \t]*/g, '$1 ')
            // do not put space after colon that separates time parts
        text = text.replace(/([۰-۹]+):\s+([۰-۹]+)/g, '$1:$2')
    }

    // should fix inside spacing for () [] {}  “” «»
    if (opts.fix_spacing_for_braces_and_quotes) {
        text = text.replace(/(\()\s*([^)]+?)\s*?(\))/g, '$1$2$3')
        text = text.replace(/(\[)\s*([^\]]+?)\s*?(\])/g, '$1$2$3')
        text = text.replace(/(\{)\s*([^}]+?)\s*?(\})/g, '$1$2$3')
        text = text.replace(/(“)\s*([^”]+?)\s*?(”)/g, '$1$2$3')
        text = text.replace(/(«)\s*([^»]+?)\s*?(»)/g, '$1$2$3')
    }

    // should replace more than one space with just a single one
    if (opts.cleanup_spacing) {
        text = text.replace(/[ ]+/g, ' ')
        text = text.replace(/([\n]+)[ \t]*/g, '$1')
    }

    // remove spaces, tabs, and new lines from the beginning and enf of file
    if (opts.cleanup_begin_and_end)
        text = text.trim();

    // bringing back urls
    if (opts.preserve_URIS) {
		text = text.replace(/__URI__PRESERVER__/g, function() {
				return URIs.shift();
            });

        }
    return text;

}

if (typeof exports === 'object') {
	module.exports = Virastar;
} else if (typeof define === 'function' && define.amd) {
	define(function() {
		return Virastar;
	});
} else {
	this.Virastar = Virastar;
}
<commit_msg>fix URI option<commit_after>function Virastar(text, options) {
    if(!(this instanceof Virastar))
        return new Virastar(text, options);
    text = text || {};
    if (typeof text == "object")
        this._init(text);
    else if (typeof text == "string") {
        this._init(options || {});
        return this.cleanup(text);
    }
    return this;
}

Virastar.prototype._init = function(options) {
    var opts = {};
    opts.fix_dashes = options.fix_dashes || true;
    opts.fix_three_dots = options.fix_three_dots || true;
    opts.fix_english_quotes = options.fix_english_quotes || true;
    opts.fix_hamzeh = options.fix_hamzeh || true;
    opts.cleanup_zwnj = options.cleanup_zwnj || true;
    opts.fix_spacing_for_braces_and_quotes = options.fix_spacing_for_braces_and_quotes || true;
    opts.fix_arabic_numbers = options.fix_arabic_numbers || true;
    opts.fix_english_numbers = options.fix_english_numbers || true;
    opts.fix_misc_non_persian_chars = options.fix_misc_non_persian_chars || true;
    opts.fix_perfix_spacing = options.fix_perfix_spacing || true;
    opts.fix_suffix_spacing = options.fix_suffix_spacing || true;
    opts.aggresive = options.aggresive || true;
    opts.cleanup_kashidas = options.cleanup_kashidas || true;
    opts.cleanup_extra_marks = options.cleanup_extra_marks || true;
    opts.cleanup_spacing = options.cleanup_spacing || true;
    opts.cleanup_begin_and_end = options.cleanup_begin_and_end || true;
    //preserve URIs
    opts.preserve_URIs = options.preserve_URIs || true;
    this.opts = opts;
}

Virastar.prototype.cleanup = function(text) {
    var opts = this.opts;

    // removing URIs bringing them back at the end of process
    if (opts.preserve_URIs) {

		var URI_regex=new RegExp( "([A-Za-z][A-Za-z0-9+\\-.]*):(?:(//)(?:((?:[A-Za-z0-9\\-._~!$&'()*+,;=:]|%[0-9A-Fa-f]{2})*)@)?((?:\\[(?:(?:(?:(?:[0-9A-Fa-f]{1,4}:){6}|::(?:[0-9A-Fa-f]{1,4}:){5}|(?:[0-9A-Fa-f]{1,4})?::(?:[0-9A-Fa-f]{1,4}:){4}|(?:(?:[0-9A-Fa-f]{1,4}:){0,1}[0-9A-Fa-f]{1,4})?::(?:[0-9A-Fa-f]{1,4}:){3}|(?:(?:[0-9A-Fa-f]{1,4}:){0,2}[0-9A-Fa-f]{1,4})?::(?:[0-9A-Fa-f]{1,4}:){2}|(?:(?:[0-9A-Fa-f]{1,4}:){0,3}[0-9A-Fa-f]{1,4})?::[0-9A-Fa-f]{1,4}:|(?:(?:[0-9A-Fa-f]{1,4}:){0,4}[0-9A-Fa-f]{1,4})?::)(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))|(?:(?:[0-9A-Fa-f]{1,4}:){0,5}[0-9A-Fa-f]{1,4})?::[0-9A-Fa-f]{1,4}|(?:(?:[0-9A-Fa-f]{1,4}:){0,6}[0-9A-Fa-f]{1,4})?::)|[Vv][0-9A-Fa-f]+\\.[A-Za-z0-9\\-._~!$&'()*+,;=:]+)\\]|(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)|(?:[A-Za-z0-9\\-._~!$&'()*+,;=]|%[0-9A-Fa-f]{2})*))(?::([0-9]*))?((?:/(?:[A-Za-z0-9\\-._~!$&'()*+,;=:@]|%[0-9A-Fa-f]{2})*)*)|/((?:(?:[A-Za-z0-9\\-._~!$&'()*+,;=:@]|%[0-9A-Fa-f]{2})+(?:/(?:[A-Za-z0-9\\-._~!$&'()*+,;=:@]|%[0-9A-Fa-f]{2})*)*)?)|((?:[A-Za-z0-9\\-._~!$&'()*+,;=:@]|%[0-9A-Fa-f]{2})+(?:/(?:[A-Za-z0-9\\-._~!$&'()*+,;=:@]|%[0-9A-Fa-f]{2})*)*)|)(?:\\?((?:[A-Za-z0-9\\-._~!$&'()*+,;=:@/?]|%[0-9A-Fa-f]{2})*))?(?:\\#((?:[A-Za-z0-9\\-._~!$&'()*+,;=:@/?]|%[0-9A-Fa-f]{2})*))?","g");
		// URI_regex by https://github.com/jhermsmeier/uri.regex

        var URIs = [];

        text = text.replace(URI_regex, function(URI) {
            URIs.push(URI);
            return "__URI__PRESERVER__";
        })

    }

    // replace double dash to ndash and triple dash to mdash
    if (opts.fix_dashes) {
        text = text.replace(/-{3}/g, '—')
        text = text.replace(/-{2}/g, '–')
    }

    // replace three dots with ellipsis
    if (opts.fix_three_dots)
        text = text.replace(/\s*\.{3,}/g, '…');

    // replace English quotes with their Persian equivalent
    if (opts.fix_english_quotes)
        text = text.replace(/(["'`]+)(.+?)(\1)/g, '«$2»');

    // should convert ه ی to ه
    if (opts.fix_hamzeh)
        text = text.replace(/(\S)(ه[\s]+[یي])(\s)/g, '$1\u0647\u0654$3');

    // remove unnecessary zwnj char that are succeeded/preceded by a space
    if (opts.cleanup_zwnj)
        text = text.replace(/\s+|\s+/g, ' ');

    var charBatchReplace = function(text, chars, Rchars) {
        var charsA = chars.split("");
        var RcharsA = Rchars.split("");
        for (var i in charsA)
            text = text.replace(new RegExp(charsA[i],'g'), RcharsA[i])
        return text;
    }

    // character replacement
    persian_numbers = "۱۲۳۴۵۶۷۸۹۰"
    arabic_numbers = "١٢٣٤٥٦٧٨٩٠"
    english_numbers = "1234567890"
    bad_chars = ",;كي%"
    good_chars = "،؛کی٪"
    if (opts.fix_english_numbers)
        text = charBatchReplace(text, english_numbers, persian_numbers);
    if (opts.fix_arabic_numbers)
        text = charBatchReplace(text, arabic_numbers, persian_numbers);
    if (opts.fix_misc_non_persian_chars)
        text = charBatchReplace(text, bad_chars, good_chars);

    // should not replace exnglish chars in english phrases
    text = text.replace(/([a-zA-Z\-_]{2,}[۰-۹]+|[۰-۹]+[a-zA-Z\-_]{2,})/g, function(match) {
        return charBatchReplace(match, persian_numbers, english_numbers);

    });

    // put zwnj between word and prefix (mi* nemi*)
    // there's a possible bug here: می and نمی could be separate nouns and not prefix
    if (opts.fix_perfix_spacing)
        text = text.replace(/\s+(ن?می)\s+/g, '\u200C\u0020$1\u200C')

    // put zwnj between word and suffix (*tar *tarin *ha *haye)
    // there's a possible bug here: های and تر could be separate nouns and not suffix
    if (opts.fix_suffix_spacing)
    text = text.replace(/\s+(تر(ی(ن)?)?|ها(ی)?)\s+/g, '\u200C$1\u0020') // in case you can not read it: \s+(tar(i(n)?)?|ha(ye)?)\s+

    // -- Aggressive Editing ------------------------------------------
    if (opts.aggresive) {

        // replace more than one ! or ? mark with just one
        if (opts.cleanup_extra_marks) {
            text = text.replace(/(!){2,}/g, '$1')
            text = text.replace(/(\u061F){2,}/g, '$1') //\u061F ==؟
        }

        // should remove all kashida
        if (opts.cleanup_kashidas)
            text = text.replace(/ـ+/g, "")

    }
    // ----------------------------------------------------------------

    // should fix outside and inside spacing for () [] {}  “” «»
    if (opts.fix_spacing_for_braces_and_quotes) {
        text = text.replace(/[ \t]*(\()\s*([^)]+?)\s*?(\))[ \t]*/g, ' $1$2$3 ')
        text = text.replace(/[ \t]*(\[)\s*([^\]]+?)\s*?(\])[ \t]*/g, ' $1$2$3 ')
        text = text.replace(/[ \t]*(\{)\s*([^}]+?)\s*?(\})[ \t]*/g, ' $1$2$3 ')
        text = text.replace(/[ \t]*(“)\s*([^”]+?)\s*?(”)[ \t]*/g, ' $1$2$3 ')
        text = text.replace(/[ \t]*(«)\s*([^»]+?)\s*?(»)[ \t]*/g, ' $1$2$3 ')
    }

    // : ; , . ! ? and their persian equivalents should have one space after and no space before
    if (opts.fix_spacing_for_braces_and_quotes) {
        text = text.replace(/[ \t]*([:;,؛،.؟!]{1})[ \t]*/g, '$1 ')
            // do not put space after colon that separates time parts
        text = text.replace(/([۰-۹]+):\s+([۰-۹]+)/g, '$1:$2')
    }

    // should fix inside spacing for () [] {}  “” «»
    if (opts.fix_spacing_for_braces_and_quotes) {
        text = text.replace(/(\()\s*([^)]+?)\s*?(\))/g, '$1$2$3')
        text = text.replace(/(\[)\s*([^\]]+?)\s*?(\])/g, '$1$2$3')
        text = text.replace(/(\{)\s*([^}]+?)\s*?(\})/g, '$1$2$3')
        text = text.replace(/(“)\s*([^”]+?)\s*?(”)/g, '$1$2$3')
        text = text.replace(/(«)\s*([^»]+?)\s*?(»)/g, '$1$2$3')
    }

    // should replace more than one space with just a single one
    if (opts.cleanup_spacing) {
        text = text.replace(/[ ]+/g, ' ')
        text = text.replace(/([\n]+)[ \t]*/g, '$1')
    }

    // remove spaces, tabs, and new lines from the beginning and enf of file
    if (opts.cleanup_begin_and_end)
        text = text.trim();

    // bringing back URIs
    if (opts.preserve_URIs) {
		text = text.replace(/__URI__PRESERVER__/g, function() {
				return URIs.shift();
            });

        }
    return text;

}

if (typeof exports === 'object') {
	module.exports = Virastar;
} else if (typeof define === 'function' && define.amd) {
	define(function() {
		return Virastar;
	});
} else {
	this.Virastar = Virastar;
}
<|endoftext|>


<commit_before>/**
 * @author Christoph Wurst <christoph@winzerhof-wurst.at>
 *
 * Mail
 *
 * This code is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License, version 3,
 * as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License, version 3,
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
 *
 */

define([
	'app',
	'cache',
	'radio',
	'backbone',
	'controller/accountcontroller',
	'models/accountcollection'
], function(Mail, Cache, Radio, Backbone, AccountController,
	AccountCollection) {
	describe('App', function() {

		beforeEach(function() {
			jasmine.Ajax.install();
			$('testcontainer').remove();
			$('body')
				.append('testcontainer')
				.append(
					'<input type="hidden" id="config-installed-version" value="0.6.1">'
					+ '<input type="hidden" id="serialized-accounts" value="">'
					+ '
Jane Doe
'
					+ '
jane@doe.cz
'
					+ '
'
					+ '
'
					+ '

'
					+ '

'
					+ '
'
					+ '
'
					+ '				<button class="settings-button" data-apps-slide-toggle="#app-settings-content"><?php p($l->t("Settings"));?></button>'
					+ '
'
					+ '

'
					+ '
'
					+ '
'
					+ '
'
					+ '
'
					+ '

'
					+ '
'
					+ '
'
					+ '
');
		});

		afterEach(function() {
			jasmine.Ajax.uninstall();
		});

		it('starts', function() {
			var resolve;
			var accountsPromise = new Promise(function(res) {
				resolve = res;
			});

			spyOn(Cache, 'init');
			spyOn(Radio.ui, 'trigger');
			spyOn(Backbone.history, 'start');
			spyOn(AccountController, 'loadAccounts').and.callFake(function() {
				return accountsPromise;
			});

			// No ajax calls so far
			expect(jasmine.Ajax.requests.count()).toBe(0);

			// Let's go…
			Mail.start();

			expect(Cache.init).toHaveBeenCalled();
			expect(Radio.ui.trigger).toHaveBeenCalledWith('content:loading', 'Loading accounts …');

			var accounts = new AccountCollection([
				{
					accountId: 44,
					name: 'Jane Doe',
					email: 'jane@doe.se'
				}
			]);
			resolve(accounts);

			accountsPromise.then(function() {
				// The promise is resolved asynchronously, so we have to use the
				// promise here too
				expect(Backbone.history.start).toHaveBeenCalled();
			});
		});
	});
});
<commit_msg>Fix failing integration test<commit_after>/**
 * @author Christoph Wurst <christoph@winzerhof-wurst.at>
 *
 * Mail
 *
 * This code is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License, version 3,
 * as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License, version 3,
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
 *
 */

define([
	'app',
	'cache',
	'radio',
	'backbone',
	'controller/accountcontroller',
	'models/accountcollection'
], function(Mail, Cache, Radio, Backbone, AccountController,
	AccountCollection) {
	describe('App', function() {

		beforeEach(function() {
			jasmine.Ajax.install();
			$('testcontainer').remove();
			$('body')
				.append('testcontainer')
				.append(
					'<input type="hidden" id="config-installed-version" value="0.6.1">'
					+ '<input type="hidden" id="serialized-accounts" value="">'
					+ '
Jane Doe
'
					+ '
jane@doe.cz
'
					+ '
'
					+ '
'
					+ '

'
					+ '

'
					+ '
'
					+ '
'
					+ '				<button class="settings-button" data-apps-slide-toggle="#app-settings-content"><?php p($l->t("Settings"));?></button>'
					+ '
'
					+ '

'
					+ '
'
					+ '
'
					+ '
'
					+ '
'
					+ '

'
					+ '
'
					+ '
'
					+ '
');
		});

		afterEach(function() {
			jasmine.Ajax.uninstall();
		});

		it('starts', function() {
			var resolve;
			var accountsPromise = new Promise(function(res) {
				resolve = res;
			});

			spyOn(Cache, 'init');
			spyOn(Radio.ui, 'trigger');
			spyOn(Backbone.history, 'start');
			spyOn(AccountController, 'loadAccounts').and.callFake(function() {
				return accountsPromise;
			});

			// No ajax calls so far
			expect(jasmine.Ajax.requests.count()).toBe(0);

			// Let's go…
			Mail.start();

			expect(Cache.init).toHaveBeenCalled();
			expect(Radio.ui.trigger).toHaveBeenCalledWith('content:loading', 'Loading accounts');

			var accounts = new AccountCollection([
				{
					accountId: 44,
					name: 'Jane Doe',
					email: 'jane@doe.se'
				}
			]);
			resolve(accounts);

			accountsPromise.then(function() {
				// The promise is resolved asynchronously, so we have to use the
				// promise here too
				expect(Backbone.history.start).toHaveBeenCalled();
			});
		});
	});
});
<|endoftext|>


<commit_before>// Copyright 2016, University of Colorado Boulder

/**
 *
 * @author Sam Reid (PhET Interactive Simulations)
 * @author Andrew Adare (PhET Interactive Simulations)
 */
define( function( require ) {
  'use strict';

  // modules
  var assertInstanceOf = require( 'PHET_IO/assertions/assertInstanceOf' );
  var phetioInherit = require( 'PHET_IO/phetioInherit' );
  var phetioNamespace = require( 'PHET_IO/phetioNamespace' );
  var TObject = require( 'PHET_IO/types/TObject' );
  var phetioEvents = require( 'PHET_IO/phetioEvents' );

  /**
   * Wrapper type for phet/tandem's TandemEmitter class.
   * Emitter for 0, 1 or 2 args
   * @param phetioArgumentTypes
   * @returns {TTandemEmitterImpl}
   * @constructor
   */
  function TTandemEmitter( phetioArgumentTypes ) {
    assert && assert( phetioArgumentTypes, 'phetioArgumentTypes should be defined' );
    return phetioInherit( TObject, 'TTandemEmitter', function TTandemEmitterImpl( tandemEmitter, phetioID ) {

      TObject.call( this, tandemEmitter, phetioID );
      assertInstanceOf( tandemEmitter, phet.tandem.TandemEmitter );

      var messageIndex = null;

      tandemEmitter.callbacksStartedEmitter.addListener( function() {
        assert && assert( arguments.length === phetioArgumentTypes.length, 'Wrong number of arguments, expected ' + phetioArgumentTypes.length + ', received ' + arguments.length );
        var p = [];
        for ( var i = 0; i < arguments.length; i++ ) {
          var a = arguments[ i ];
          p.push( a );
        }
        var parameters = { arguments: p };
        messageIndex = phetioEvents.start( 'model', phetioID, TTandemEmitter( phetioArgumentTypes ), 'emitted', parameters );
      } );

      tandemEmitter.callbacksEndedEmitter.addListener( function() {
        assert && assert( arguments.length === 0, 'Wrong number of arguments, expected ' + phetioArgumentTypes.length + ', received ' + arguments.length );
        messageIndex && phetioEvents.end( messageIndex );
      } );
    }, {}, {
      documentation: 'Emitters indicate when events have occurred, with optional arguments describing the event',
      events: [ 'emitted' ]
    } );
  }

  phetioNamespace.register( 'TTandemEmitter', TTandemEmitter );

  return TTandemEmitter;
} );
<commit_msg>Updated jsdoc, see https://github.com/phetsims/phet-io/issues/522<commit_after>// Copyright 2016, University of Colorado Boulder

/**
 *
 * @author Sam Reid (PhET Interactive Simulations)
 * @author Andrew Adare (PhET Interactive Simulations)
 */
define( function( require ) {
  'use strict';

  // modules
  var assertInstanceOf = require( 'PHET_IO/assertions/assertInstanceOf' );
  var phetioInherit = require( 'PHET_IO/phetioInherit' );
  var phetioNamespace = require( 'PHET_IO/phetioNamespace' );
  var TObject = require( 'PHET_IO/types/TObject' );
  var phetioEvents = require( 'PHET_IO/phetioEvents' );

  /**
   * Wrapper type for phet/tandem's TandemEmitter class.
   * Emitter for 0, 1 or 2 args
   * @param {function[]} phetioArgumentTypes
   * @returns {TTandemEmitterImpl}
   * @constructor
   */
  function TTandemEmitter( phetioArgumentTypes ) {
    assert && assert( phetioArgumentTypes, 'phetioArgumentTypes should be defined' );
    return phetioInherit( TObject, 'TTandemEmitter', function TTandemEmitterImpl( tandemEmitter, phetioID ) {

      TObject.call( this, tandemEmitter, phetioID );
      assertInstanceOf( tandemEmitter, phet.tandem.TandemEmitter );

      var messageIndex = null;

      tandemEmitter.callbacksStartedEmitter.addListener( function() {
        assert && assert( arguments.length === phetioArgumentTypes.length, 'Wrong number of arguments, expected ' + phetioArgumentTypes.length + ', received ' + arguments.length );
        var p = [];
        for ( var i = 0; i < arguments.length; i++ ) {
          var a = arguments[ i ];
          p.push( a );
        }
        var parameters = { arguments: p };
        messageIndex = phetioEvents.start( 'model', phetioID, TTandemEmitter( phetioArgumentTypes ), 'emitted', parameters );
      } );

      tandemEmitter.callbacksEndedEmitter.addListener( function() {
        assert && assert( arguments.length === 0, 'Wrong number of arguments, expected ' + phetioArgumentTypes.length + ', received ' + arguments.length );
        messageIndex && phetioEvents.end( messageIndex );
      } );
    }, {}, {
      documentation: 'Emitters indicate when events have occurred, with optional arguments describing the event',
      events: [ 'emitted' ]
    } );
  }

  phetioNamespace.register( 'TTandemEmitter', TTandemEmitter );

  return TTandemEmitter;
} );
<|endoftext|>


<commit_before>requirejs.config({
    paths: {
        jquery: '../vendor/bower/jquery/jquery',
        backbone: '../vendor/bower/backbone/backbone',
        underscore: '../vendor/bower/lodash/dist/lodash.underscore',
        layoutmanager: '../vendor/bower/layoutmanager/backbone.layoutmanager'
    },
    shim: {
        backbone: {
            deps: ['underscore','jquery'],
            exports: 'Backbone'
        },
        layoutmanager: ['backbone']
    }
});
<commit_msg>update path to jquery<commit_after>requirejs.config({
    paths: {
        jquery: '../vendor/bower/jquery/dist/jquery',
        backbone: '../vendor/bower/backbone/backbone',
        underscore: '../vendor/bower/lodash/dist/lodash.underscore',
        layoutmanager: '../vendor/bower/layoutmanager/backbone.layoutmanager'
    },
    shim: {
        backbone: {
            deps: ['underscore','jquery'],
            exports: 'Backbone'
        },
        layoutmanager: ['backbone']
    }
});
<|endoftext|>


<commit_before>/**
ZLocator
**/

module.exports = zlocator;

var path = require('path');
var EE = require('events').EventEmitter;
var inherits = require('inherits');

var PromiseImpl = require('bluebird');
var Locator = require('locator');
var LocatorHandlebars = require('locator-handlebars');
var LocatorYUI = require('locator-yui');
var Handlebars = require('yui/handlebars').Handlebars;

var clean = require('./options').clean;
var extend = require('util')._extend;

function zlocator(options, cb) {
    return new ZLocator(options, cb).promise;
}

zlocator.ZLocator = ZLocator;
inherits(ZLocator, EE);
function ZLocator(options, cb) {
    EE.call(this);
    this.options = clean(options || {});
    this.promise = this.getLocator().then(this.parseBundle).nodeify(cb);
}

ZLocator.prototype.getLocator = function () {
    var locator = new Locator({
        applicationDirectory: this.options.applicationDirectory,
        buildDirectory: this.options.buildDirectory,
        recursiveSearchPackageJson: true
    });

    return PromiseImpl.resolve(locator).bind(this)
        .then(this.plugHandlebars)
        .then(this.plugYUI);
};

ZLocator.prototype._hbsNameParser = function () {
    var templateDirectory = this.options.templateDirectory;
    return function hbsNameParser(sourcePath) {
        // return path.basename(sourcePath, path.extname(sourcePath));
        return path.join(
            path.dirname(
                path.relative(templateDirectory, sourcePath)
            ),
            path.basename(sourcePath, path.extname(sourcePath))
        ).split(path.sep).join('-');
    };
};

ZLocator.prototype.plugHandlebars = function (locator) {
    var loch = new LocatorHandlebars({
        prefix: this.options.prefix,
        format: 'yui',
        handlebars: Handlebars
    });

    loch.describe.extensions.push('mustache');
    loch.nameParser = this._hbsNameParser();

    return locator.plug(loch);
};

ZLocator.prototype.plugYUI = function (locator) {
    var shifterOptions = {
            quiet: this.options.quiet
        };
    if (this.options.shifterOptions) {
        shifterOptions = extend(shifterOptions, this.options.shifterOptions);
    }
    console.log(this.options);
    var locy = new LocatorYUI({
        loaderTemplatePath: this.options.loaderTemplatePath,
        coverage: true,
        shifterOptions: shifterOptions
    });

    return locator.plug(locy);
};

ZLocator.prototype.parseBundle = function (locator) {
    return locator.parseBundle(this.options.applicationDirectory || this.options.cwd, {
        bundleBuildDirectoryParser: function (bundle) {
            // return bundle.name + '-' + bundle.version; // default
            return bundle.name;
        }
    });
};
<commit_msg>Add templateDirectory filter to locator-handlebars instance<commit_after>/**
ZLocator
**/

module.exports = zlocator;

var path = require('path');
var EE = require('events').EventEmitter;
var inherits = require('inherits');

var PromiseImpl = require('bluebird');
var Locator = require('locator');
var LocatorHandlebars = require('locator-handlebars');
var LocatorYUI = require('locator-yui');
var Handlebars = require('yui/handlebars').Handlebars;

var clean = require('./options').clean;
var extend = require('util')._extend;

function zlocator(options, cb) {
    return new ZLocator(options, cb).promise;
}

zlocator.ZLocator = ZLocator;
inherits(ZLocator, EE);
function ZLocator(options, cb) {
    EE.call(this);
    this.options = clean(options || {});
    this.promise = this.getLocator().then(this.parseBundle).nodeify(cb);
}

ZLocator.prototype.getLocator = function () {
    var locator = new Locator({
        applicationDirectory: this.options.applicationDirectory,
        buildDirectory: this.options.buildDirectory,
        recursiveSearchPackageJson: true
    });

    return PromiseImpl.resolve(locator).bind(this)
        .then(this.plugHandlebars)
        .then(this.plugYUI);
};

ZLocator.prototype._hbsNameParser = function () {
    var templateDirectory = this.options.templateDirectory;
    return function hbsNameParser(sourcePath) {
        // return path.basename(sourcePath, path.extname(sourcePath));
        return path.join(
            path.dirname(
                path.relative(templateDirectory, sourcePath)
            ),
            path.basename(sourcePath, path.extname(sourcePath))
        ).split(path.sep).join('-');
    };
};

ZLocator.prototype.plugHandlebars = function (locator) {
    var loch = new LocatorHandlebars({
        prefix: this.options.prefix,
        format: 'yui',
        handlebars: Handlebars
    });

    loch.describe.extensions.push('mustache');
    loch.describe.path = this.options.templateDirectory;
    loch.nameParser = this._hbsNameParser();

    return locator.plug(loch);
};

ZLocator.prototype.plugYUI = function (locator) {
    var shifterOptions = {
            quiet: this.options.quiet
        };
    if (this.options.shifterOptions) {
        shifterOptions = extend(shifterOptions, this.options.shifterOptions);
    }
    console.log(this.options);
    var locy = new LocatorYUI({
        loaderTemplatePath: this.options.loaderTemplatePath,
        coverage: true,
        shifterOptions: shifterOptions
    });

    return locator.plug(locy);
};

ZLocator.prototype.parseBundle = function (locator) {
    return locator.parseBundle(this.options.applicationDirectory || this.options.cwd, {
        bundleBuildDirectoryParser: function (bundle) {
            // return bundle.name + '-' + bundle.version; // default
            return bundle.name;
        }
    });
};
<|endoftext|>


<commit_before>/**
 * @module jsdoc/util/templateHelper
 */

var hash = require('pajhome/hash');
var dictionary = require('jsdoc/tag/dictionary');

exports.globalName = 'global';
exports.fileExtension = '.html';

/** Find symbol {@link ...} and {@tutorial ...} strings in text and turn into html links */
exports.resolveLinks = function(str) {
    str = str.replace(/(?:\[(.+?)\])?\{@link +(.+?)\}/gi,
        function(match, content, longname) {
            return toLink(longname, content);
        }
    );

    str = str.replace(/(?:\[(.+?)\])?\{@tutorial +(.+?)\}/gi,
        function(match, content, tutorial) {
            return toTutorial(tutorial, content);
        }
    );

    return str;
}

// two-way lookup
var linkMap = {
    longnameToUrl: {},
    urlToLongname: {}
};

exports.registerLink = function(longname, url) {
	//todo if longname or url is named like a methods in Object.prototype explodes
    linkMap.longnameToUrl[longname] = url;
    linkMap.urlToLongname[url] = longname;
}

// each container gets its own html file
exports.containers = ['class', 'module', 'external', 'namespace', 'mixin'];

/** Turn a doclet into a URL. */
exports.createLink = function(doclet) {
    var url = '';

    if (exports.containers.indexOf(doclet.kind) < 0) {
        var longname = doclet.longname,
            filename = strToFilename(doclet.memberof || exports.globalName); // TODO handle name collisions

        url = filename + exports.fileExtension + '#' + getNamespace(doclet.kind) + doclet.name;
    }
    else {
        var longname = doclet.longname,
            filename = strToFilename(longname); // TODO handle name collisions

        url = filename + exports.fileExtension;
    }

    return url;
}

function getNamespace(kind) {
    if (dictionary.isNamespace(kind)) {
        return kind+':';
    }
    return '';
}

function strToFilename(str) {
    if ( /[^$a-z0-9._-]/i.test(str) ) {
        return hash.hex_md5(str).substr(0, 10);
    }
    return str;
}

function makeFilenameUnique(filename) {
    return filename;
}

function toLink(longname, content) {
    if (!longname) {
        throw new Error('Missing required parameter: url');
    }

    // Has link been specified manually?
    var url;
    if (/^(http|ftp)s?:/.test(longname)) {
        url = longname;

        // Has link text been specified {@link http://github.com|GitHub Website}
        var split = url.indexOf('|');
        if (split !== -1) {
            content = url.substr(split + 1);
            url = url.substr(0, split);
        }
    }
    else {
	    url = linkMap.longnameToUrl[longname];
	}

    content = content || longname;

    if (!url) {
        return content;
    }
    else {
        return ''+content+'';
    }
}

/** @external {jsdoc.tutorial.Tutorial} */
var tutorials;

/** Sets tutorials map.
    @param {jsdoc.tutorial.Tutorial} root - Root tutorial node.
 */
exports.setTutorials = function(root) {
    tutorials = root;
};

exports.toTutorial = toTutorial = function(tutorial, content) {
    if (!tutorial) {
        throw new Error('Missing required parameter: tutorial');
    }

    var node = tutorials.getByName(tutorial);
    // no such tutorial
    if (!node) {
        return 'Tutorial: '+tutorial+'';
    }

    content = content || node.title;

    return ''+content+'';
}

exports.longnameToUrl = linkMap.longnameToUrl;

exports.tutorialToUrl = function(tutorial) {
    var node = tutorials.getByName(tutorial);
    // no such tutorial
    if (!node) {
        throw new Error('No such tutorial: '+tutorial);
    }

    return 'tutorial-'+strToFilename(node.name)+exports.fileExtension;
};
<commit_msg>Removed dependency on pajhome/hash, as I can't make it work. Instead of creating MD5's, simply replace illegal chars with _.<commit_after>/**
 * @module jsdoc/util/templateHelper
 */

// var hash = require('pajhome/hash');
var dictionary = require('jsdoc/tag/dictionary');

exports.globalName = 'global';
exports.fileExtension = '.html';

/** Find symbol {@link ...} and {@tutorial ...} strings in text and turn into html links */
exports.resolveLinks = function(str) {
    str = str.replace(/(?:\[(.+?)\])?\{@link +(.+?)\}/gi,
        function(match, content, longname) {
            return toLink(longname, content);
        }
    );

    str = str.replace(/(?:\[(.+?)\])?\{@tutorial +(.+?)\}/gi,
        function(match, content, tutorial) {
            return toTutorial(tutorial, content);
        }
    );

    return str;
}

// two-way lookup
var linkMap = {
    longnameToUrl: {},
    urlToLongname: {}
};

exports.registerLink = function(longname, url) {
	//todo if longname or url is named like a methods in Object.prototype explodes
    linkMap.longnameToUrl[longname] = url;
    linkMap.urlToLongname[url] = longname;
}

// each container gets its own html file
exports.containers = ['class', 'module', 'external', 'namespace', 'mixin'];

/** Turn a doclet into a URL. */
exports.createLink = function(doclet) {
    var url = '';

    if (exports.containers.indexOf(doclet.kind) < 0) {
        var longname = doclet.longname,
            filename = strToFilename(doclet.memberof || exports.globalName); // TODO handle name collisions

        url = filename + exports.fileExtension + '#' + getNamespace(doclet.kind) + doclet.name;
    }
    else {
        var longname = doclet.longname,
            filename = strToFilename(longname); // TODO handle name collisions

        url = filename + exports.fileExtension;
    }

    return url;
}

function getNamespace(kind) {
    if (dictionary.isNamespace(kind)) {
        return kind+':';
    }
    return '';
}

function strToFilename(str) {
    if ( /[^$a-z0-9._-]/i.test(str) ) {
        // return hash.hex_md5(str).substr(0, 10);
        return str.replace( /[^$a-z0-9._-]/, "_", "g" );
    }
    return str;
}

function makeFilenameUnique(filename) {
    return filename;
}

function toLink(longname, content) {
    if (!longname) {
        throw new Error('Missing required parameter: url');
    }

    // Has link been specified manually?
    var url;
    if (/^(http|ftp)s?:/.test(longname)) {
        url = longname;

        // Has link text been specified {@link http://github.com|GitHub Website}
        var split = url.indexOf('|');
        if (split !== -1) {
            content = url.substr(split + 1);
            url = url.substr(0, split);
        }
    }
    else {
	    url = linkMap.longnameToUrl[longname];
	}

    content = content || longname;

    if (!url) {
        return content;
    }
    else {
        return ''+content+'';
    }
}

/** @external {jsdoc.tutorial.Tutorial} */
var tutorials;

/** Sets tutorials map.
    @param {jsdoc.tutorial.Tutorial} root - Root tutorial node.
 */
exports.setTutorials = function(root) {
    tutorials = root;
};

exports.toTutorial = toTutorial = function(tutorial, content) {
    if (!tutorial) {
        throw new Error('Missing required parameter: tutorial');
    }

    var node = tutorials.getByName(tutorial);
    // no such tutorial
    if (!node) {
        return 'Tutorial: '+tutorial+'';
    }

    content = content || node.title;

    return ''+content+'';
}

exports.longnameToUrl = linkMap.longnameToUrl;

exports.tutorialToUrl = function(tutorial) {
    var node = tutorials.getByName(tutorial);
    // no such tutorial
    if (!node) {
        throw new Error('No such tutorial: '+tutorial);
    }

    return 'tutorial-'+strToFilename(node.name)+exports.fileExtension;
};
<|endoftext|>