<commit_before>var chai = require('chai');
var add = require('../../../src/add/index');
var path = require('path');
var fse = require('fs-extra');
var glob = require('glob');
var dest = 'test' + path.sep + 'tmp';

// resourceType, resourceName, template, destName, dest, options, callback
describe('add', function () {

    var expected = 0;
    var completed = 0;

    function onDone (done) {
        completed++;
        if (expected === completed) {
            done();
        }
    }

    beforeEach(function (done) {
        // remove default template dir to ensure that create command actually
        // copied the files
        fse.remove(path.resolve(dest), function (err) {
            if (err) {
                throw err;
            }

            expected = 0;
            completed = 0;
            done();
        });
    });

    it('should add a component', function (done) {
        expected = 3;

        // add('component', null, null, 'foo', 'test/tmp', null, function (err, result) {
        //     var pattern = dest + path.sep + 'components' + path.sep + 'foo' + path.sep + '**/*.*';
        //     chai.expect(err).to.be.null;
        //     glob(pattern, null, function (err, files) {
        //         chai.expect(files.length).to.be.equal(1);
        //         chai.expect(files[0]).to.be.equal('test/tmp/components/foo/views/index.hbs');
        //         onDone(done);
        //     });
        // });

        add('component', null, null, 'bar', 'test/tmp', { view: true, controller: true }, function (err, result) {
            var pattern = dest + path.sep + 'components' + path.sep + 'bar' + path.sep + '**/*.*';

            chai.expect(err).to.be.null;
            glob(pattern, null, function (err, files) {
                chai.expect(files.length).to.be.equal(3);
                chai.expect(files[0]).to.be.equal('test/tmp/components/bar/controller.js');
                chai.expect(files[1]).to.be.equal('test/tmp/components/bar/views/index.hbs');
                chai.expect(files[2]).to.be.equal('test/tmp/components/bar/views/index.js');
                onDone(done);
            });
        });

        add('component', 'hello', null, 'baz', 'test/tmp', null, function (err, result) {
            var pattern = dest + path.sep + 'components' + path.sep + 'baz' + path.sep + '**/*.*';
            chai.expect(err).to.be.null;
            glob(pattern, null, function (err, files) {
                chai.expect(files.length).to.be.equal(1);
                chai.expect(files[0]).to.be.equal('test/tmp/components/baz/views/index.hbs');
                onDone(done);
            });
        });

        add('component', 'hello', null, 'foobar', 'test/tmp', { view: true, controller: true }, function (err, result) {
            var pattern = dest + path.sep + 'components' + path.sep + 'foobar' + path.sep + '**/*.*';

            chai.expect(err).to.be.null;
            glob(pattern, null, function (err, files) {
                chai.expect(files.length).to.be.equal(3);
                chai.expect(files[0]).to.be.equal('test/tmp/components/foobar/controller.js');
                chai.expect(files[1]).to.be.equal('test/tmp/components/foobar/views/index.hbs');
                chai.expect(files[2]).to.be.equal('test/tmp/components/foobar/views/index.js');
                onDone(done);
            });
        });
    });

    it('should add a model', function (done) {
        expected = 4;

        add('model', null, null, 'foo', 'test/tmp', null, function (err, result) {
            var pattern = dest + path.sep + 'models' + path.sep + 'foo' + path.sep + '**/*.*';

            chai.expect(err).to.be.null;
            glob(pattern, null, function (err, files) {
                chai.expect(files.length).to.be.equal(1);
                chai.expect(files[0]).to.be.equal('test/tmp/models/foo/model.js');
                onDone(done);
            });
        });

        add('model', null, null, 'bar', 'test/tmp', { syncher: true }, function (err, result) {
            var pattern = dest + path.sep + 'models' + path.sep + 'bar' + path.sep + '**/*.*';

            chai.expect(err).to.be.null;
            glob(pattern, null, function (err, files) {
                chai.expect(files.length).to.be.equal(2);
                chai.expect(files[0]).to.be.equal('test/tmp/models/bar/model.js');
                chai.expect(files[1]).to.be.equal('test/tmp/models/bar/server/syncher.js');
                onDone(done);
            });
        });

        add('model', 'model', null, 'baz', 'test/tmp', null, function (err, result) {
            var pattern = dest + path.sep + 'models' + path.sep + 'baz' + path.sep + '**/*.*';

            chai.expect(err).to.be.null;
            glob(pattern, null, function (err, files) {
                chai.expect(files.length).to.be.equal(1);
                chai.expect(files[0]).to.be.equal('test/tmp/models/baz/model.js');
                onDone(done);
            });
        });

        add('model', 'model', null, 'foobar', 'test/tmp', { syncher: true }, function (err, result) {
            var pattern = dest + path.sep + 'models' + path.sep + 'foobar' + path.sep + '**/*.*';

            chai.expect(err).to.be.null;
            glob(pattern, null, function (err, files) {
                chai.expect(files.length).to.be.equal(2);
                chai.expect(files[0]).to.be.equal('test/tmp/models/foobar/model.js');
                chai.expect(files[1]).to.be.equal('test/tmp/models/foobar/server/syncher.js');
                onDone(done);
            });
        });
    });

    it('should add a collection', function (done) {
        expected = 4;

        add('collection', null, null, 'foo', 'test/tmp', null, function (err, result) {
            var pattern = dest + path.sep + 'models' + path.sep + 'foo' + path.sep + '**/*.*';

            chai.expect(err).to.be.null;
            glob(pattern, null, function (err, files) {
                chai.expect(files.length).to.be.equal(1);
                chai.expect(files[0]).to.be.equal('test/tmp/models/foo/collection.js');
                onDone(done);
            });
        });

        add('collection', null, null, 'bar', 'test/tmp', { syncher: true }, function (err, result) {
            var pattern = dest + path.sep + 'models' + path.sep + 'bar' + path.sep + '**/*.*';

            chai.expect(err).to.be.null;
            glob(pattern, null, function (err, files) {
                chai.expect(files.length).to.be.equal(2);
                chai.expect(files[0]).to.be.equal('test/tmp/models/bar/collection.js');
                chai.expect(files[1]).to.be.equal('test/tmp/models/bar/server/syncher.js');
                onDone(done);
            });
        });

        add('collection', 'collection', null, 'baz', 'test/tmp', null, function (err, result) {
            var pattern = dest + path.sep + 'models' + path.sep + 'baz' + path.sep + '**/*.*';

            chai.expect(err).to.be.null;
            glob(pattern, null, function (err, files) {
                chai.expect(files.length).to.be.equal(1);
                chai.expect(files[0]).to.be.equal('test/tmp/models/baz/collection.js');
                onDone(done);
            });
        });

        add('collection', 'collection', null, 'foobar', 'test/tmp', { syncher: true }, function (err, result) {
            var pattern = dest + path.sep + 'models' + path.sep + 'foobar' + path.sep + '**/*.*';

            chai.expect(err).to.be.null;
            glob(pattern, null, function (err, files) {
                chai.expect(files.length).to.be.equal(2);
                chai.expect(files[0]).to.be.equal('test/tmp/models/foobar/collection.js');
                chai.expect(files[1]).to.be.equal('test/tmp/models/foobar/server/syncher.js');
                onDone(done);
            });
        });

    });

});<commit_msg>add back part of test<commit_after>var chai = require('chai');
var add = require('../../../src/add/index');
var path = require('path');
var fse = require('fs-extra');
var glob = require('glob');
var dest = 'test' + path.sep + 'tmp';

// resourceType, resourceName, template, destName, dest, options, callback
describe('add', function () {

    var expected = 0;
    var completed = 0;

    function onDone (done) {
        completed++;
        if (expected === completed) {
            done();
        }
    }

    beforeEach(function (done) {
        // remove default template dir to ensure that create command actually
        // copied the files
        fse.remove(path.resolve(dest), function (err) {
            if (err) {
                throw err;
            }

            expected = 0;
            completed = 0;
            done();
        });
    });

    it('should add a component', function (done) {
        expected = 3;

        add('component', null, null, 'foo', 'test/tmp', null, function (err, result) {
            var pattern = dest + path.sep + 'components' + path.sep + 'foo' + path.sep + '**/*.*';
            chai.expect(err).to.be.null;
            // glob(pattern, null, function (err, files) {
            //     chai.expect(files.length).to.be.equal(1);
            //     chai.expect(files[0]).to.be.equal('test/tmp/components/foo/views/index.hbs');
            //     onDone(done);
            // });
        });

        add('component', null, null, 'bar', 'test/tmp', { view: true, controller: true }, function (err, result) {
            var pattern = dest + path.sep + 'components' + path.sep + 'bar' + path.sep + '**/*.*';

            chai.expect(err).to.be.null;
            glob(pattern, null, function (err, files) {
                chai.expect(files.length).to.be.equal(3);
                chai.expect(files[0]).to.be.equal('test/tmp/components/bar/controller.js');
                chai.expect(files[1]).to.be.equal('test/tmp/components/bar/views/index.hbs');
                chai.expect(files[2]).to.be.equal('test/tmp/components/bar/views/index.js');
                onDone(done);
            });
        });

        add('component', 'hello', null, 'baz', 'test/tmp', null, function (err, result) {
            var pattern = dest + path.sep + 'components' + path.sep + 'baz' + path.sep + '**/*.*';
            chai.expect(err).to.be.null;
            glob(pattern, null, function (err, files) {
                chai.expect(files.length).to.be.equal(1);
                chai.expect(files[0]).to.be.equal('test/tmp/components/baz/views/index.hbs');
                onDone(done);
            });
        });

        add('component', 'hello', null, 'foobar', 'test/tmp', { view: true, controller: true }, function (err, result) {
            var pattern = dest + path.sep + 'components' + path.sep + 'foobar' + path.sep + '**/*.*';

            chai.expect(err).to.be.null;
            glob(pattern, null, function (err, files) {
                chai.expect(files.length).to.be.equal(3);
                chai.expect(files[0]).to.be.equal('test/tmp/components/foobar/controller.js');
                chai.expect(files[1]).to.be.equal('test/tmp/components/foobar/views/index.hbs');
                chai.expect(files[2]).to.be.equal('test/tmp/components/foobar/views/index.js');
                onDone(done);
            });
        });
    });

    it('should add a model', function (done) {
        expected = 4;

        add('model', null, null, 'foo', 'test/tmp', null, function (err, result) {
            var pattern = dest + path.sep + 'models' + path.sep + 'foo' + path.sep + '**/*.*';

            chai.expect(err).to.be.null;
            glob(pattern, null, function (err, files) {
                chai.expect(files.length).to.be.equal(1);
                chai.expect(files[0]).to.be.equal('test/tmp/models/foo/model.js');
                onDone(done);
            });
        });

        add('model', null, null, 'bar', 'test/tmp', { syncher: true }, function (err, result) {
            var pattern = dest + path.sep + 'models' + path.sep + 'bar' + path.sep + '**/*.*';

            chai.expect(err).to.be.null;
            glob(pattern, null, function (err, files) {
                chai.expect(files.length).to.be.equal(2);
                chai.expect(files[0]).to.be.equal('test/tmp/models/bar/model.js');
                chai.expect(files[1]).to.be.equal('test/tmp/models/bar/server/syncher.js');
                onDone(done);
            });
        });

        add('model', 'model', null, 'baz', 'test/tmp', null, function (err, result) {
            var pattern = dest + path.sep + 'models' + path.sep + 'baz' + path.sep + '**/*.*';

            chai.expect(err).to.be.null;
            glob(pattern, null, function (err, files) {
                chai.expect(files.length).to.be.equal(1);
                chai.expect(files[0]).to.be.equal('test/tmp/models/baz/model.js');
                onDone(done);
            });
        });

        add('model', 'model', null, 'foobar', 'test/tmp', { syncher: true }, function (err, result) {
            var pattern = dest + path.sep + 'models' + path.sep + 'foobar' + path.sep + '**/*.*';

            chai.expect(err).to.be.null;
            glob(pattern, null, function (err, files) {
                chai.expect(files.length).to.be.equal(2);
                chai.expect(files[0]).to.be.equal('test/tmp/models/foobar/model.js');
                chai.expect(files[1]).to.be.equal('test/tmp/models/foobar/server/syncher.js');
                onDone(done);
            });
        });
    });

    it('should add a collection', function (done) {
        expected = 4;

        add('collection', null, null, 'foo', 'test/tmp', null, function (err, result) {
            var pattern = dest + path.sep + 'models' + path.sep + 'foo' + path.sep + '**/*.*';

            chai.expect(err).to.be.null;
            glob(pattern, null, function (err, files) {
                chai.expect(files.length).to.be.equal(1);
                chai.expect(files[0]).to.be.equal('test/tmp/models/foo/collection.js');
                onDone(done);
            });
        });

        add('collection', null, null, 'bar', 'test/tmp', { syncher: true }, function (err, result) {
            var pattern = dest + path.sep + 'models' + path.sep + 'bar' + path.sep + '**/*.*';

            chai.expect(err).to.be.null;
            glob(pattern, null, function (err, files) {
                chai.expect(files.length).to.be.equal(2);
                chai.expect(files[0]).to.be.equal('test/tmp/models/bar/collection.js');
                chai.expect(files[1]).to.be.equal('test/tmp/models/bar/server/syncher.js');
                onDone(done);
            });
        });

        add('collection', 'collection', null, 'baz', 'test/tmp', null, function (err, result) {
            var pattern = dest + path.sep + 'models' + path.sep + 'baz' + path.sep + '**/*.*';

            chai.expect(err).to.be.null;
            glob(pattern, null, function (err, files) {
                chai.expect(files.length).to.be.equal(1);
                chai.expect(files[0]).to.be.equal('test/tmp/models/baz/collection.js');
                onDone(done);
            });
        });

        add('collection', 'collection', null, 'foobar', 'test/tmp', { syncher: true }, function (err, result) {
            var pattern = dest + path.sep + 'models' + path.sep + 'foobar' + path.sep + '**/*.*';

            chai.expect(err).to.be.null;
            glob(pattern, null, function (err, files) {
                chai.expect(files.length).to.be.equal(2);
                chai.expect(files[0]).to.be.equal('test/tmp/models/foobar/collection.js');
                chai.expect(files[1]).to.be.equal('test/tmp/models/foobar/server/syncher.js');
                onDone(done);
            });
        });

    });

});<|endoftext|>


<commit_before>var fs = require('fs'),
	path = require('path'),
	colors = require('colors'),
	TU = require('../lib/testUtils'),
	CONST = require('../../Alloy/common/constants'),
	_ = require('../../Alloy/lib/alloy/underscore')._,
	uglifyjs = require('uglify-js'),
	optimizer = require('../../Alloy/commands/compile/optimizer');

var tests = [
	// make sure we didn't break normal conditionals and assigments
	['var a = Ti.Platform.name', 'var a="<%= Ti_Platform_name %>"'],
	['var a = Titanium.Platform.name', 'var a="<%= Titanium_Platform_name %>"'],
	['var a = Ti.Platform.name=="<%= Titanium_Platform_name %>" ? 1 : 0', 'var a=1'],
	['var a = Ti.Platform.name=="<%= Titanium_Platform_name %>", b', 'var a=!0,b'],
	['var a = Ti.Platform.name=="<%= Titanium_Platform_name %>", b, c = 2', 'var a=!0,b,c=2'],
	['var a = Ti.Platform.name=="<%= Titanium_Platform_name %>"', 'var a=!0'],
	['var a = Ti.Platform.name!="iPhone OS"', 'var a=!1', ['ios']],
	['var a = Ti.Platform.name=="iPhone OS"', 'var a=!1', notPlatform('ios')],
	['var a, b = Ti.Platform.name=="<%= Titanium_Platform_name %>", c = 2;', 'var a,b=!0,c=2'],
	['var a = "<%= Titanium_Platform_name %>"==Ti.Platform.name ? 1 : 0', 'var a=1'],
	['var a = "<%= Titanium_Platform_name %>"==Ti.Platform.name, b', 'var a=!0,b'],
	['var a = "<%= Titanium_Platform_name %>"==Ti.Platform.name, b, c = 2', 'var a=!0,b,c=2'],
	['var a = "<%= Titanium_Platform_name %>"==Ti.Platform.name', 'var a=!0'],
	['var a = "iPhone OS"!=Ti.Platform.name', 'var a=!1', ['ios']],
	['var a = "iPhone OS"==Ti.Platform.name', 'var a=!1', notPlatform('ios')],
	['var a, b = "<%= Titanium_Platform_name %>"==Ti.Platform.name, c = 2;', 'var a,b=!0,c=2'],
	['var a = "1"', 'var a="1"'],
	['var a = true', 'var a=!0'],
	['var a = 1', 'var a=1'],
	['var a', 'var a'],
	['var a = {}', 'var a={}'],
	['var a = new Object', 'var a=new Object'],
	['var a = new Object()', 'var a=new Object'],
	['var a = Ti.Platform.name', 'var a="<%= Ti_Platform_name %>"'],
	['var a = Ti.Platform.osname', 'var a="android"', ['android']],
	['var a = Ti.Platform.osname', 'var a="mobileweb"', ['mobileweb']],
	['var a, b = 1, c = 2;', 'var a,b=1,c=2'],
	['var a = 1;', 'var a=1'],
	['var a =+1;', 'var a=1'],
	['var a =1+1;', 'var a=2'],
	['var a = 1.0;', 'var a=1'],
	['var a = 1.02;', 'var a=1.02'],
	['var a = -1.02;', 'var a=-1.02'],
	['var a = !1', 'var a=!1'],
	['var a = true ? 1 : 0;', 'var a=1'],
	["var num = isNaN(amount) || amount === '' || amount === null ? 0.00 : amount;", 'var num=isNaN(amount)||amount===""||amount===null?0:amount'],

	// make sure we didn't break normal if conditions
	['if (true) { var a = 1; } else { var a = 2; }', "var a=1"],

	// check platform conditionals (if/else)
	["if (Titanium.Platform.name === '<%= Titanium_Platform_name %>'){ var a = 1; } else { var a = 2; }","var a=1"],
	["if (Titanium.Platform.name !== '<%= Titanium_Platform_name %>'){ var a = 1; } else { var a = 2; }","var a=2"],
	["if (Titanium.Platform['name'] == '<%= Titanium_Platform_name %>'){ var a = 1; } else { var a = 2; }","var a=1"],
	["if (Titanium.Platform.name !== '<%= Titanium_Platform_name %>'){ var a = 1; } else { var a = 2; }","var a=2"],
	["if (Titanium.Platform['name'] !== '<%= Titanium_Platform_name %>'){ var a = 1; } else { var a = 2; }","var a=2"],

	// check platform conditional assignments
	["var platform = Ti.Platform['name'] === '<%= Ti_Platform_name %>'", "var platform=!0"],
	["var platform = Ti.Platform[\"name\"] === '<%= Ti_Platform_name %>'", "var platform=!0"],
	["var platform = Ti.Platform.name === '<%= Ti_Platform_name %>'", "var platform=!0"],
	["var platform = Ti.Platform.name === 'iPhone OS'", "var platform=!1", notPlatform('ios')],
	["var platform = (Ti.Platform.name === '<%= Ti_Platform_name %>')", "var platform=!0"],
	["var platform = (Ti.Platform.name === '<%= Ti_Platform_name %>') ? 1 : 0", "var platform=1"],
	["var platform = (Ti.Platform.name === '<%= Ti_Platform_name %>') ? true : false", "var platform=!0"],
	["var platform = (Ti.Platform.name === 'iPhone OS') ? 1 : 0", "var platform=0", notPlatform('ios')],
	["var platform = (Ti.Platform.name === 'iPhone OS') ? true : false", "var platform=!1", notPlatform('ios')],
	["var platform = (Ti.Platform.name == '<%= Ti_Platform_name %>') ? 'true' : 'false'", "var platform=\"true\""],
	["var platform = (Ti.Platform.name == 'iPhone OS') ? 'true' : 'false'", "var platform=\"false\"", notPlatform('ios')],
	["var platform = (Ti.Platform.osname == 'android') ? 'true' : 'false'", "var platform=\"true\"", ['android']],
	["var platform = (Ti.Platform.osname == \"iphone\") ? 1 : 0", "var platform=0", notPlatform('ios')],
	["var platform = (Ti.Platform.osname == \"iphone\") ? 1 : 0", "var platform=Ti.Platform.osname==\"iphone\"?1:0", ['ios']],

	// check identities
	["var a = Ti.Platform.name === Titanium.Platform.name","var a=!0"],

	// shouldn't attempt to process anything other than strings
	["if (Ti.Platform.name === couldBeAnything()) { var a = 1; } else { var a = 2; }","if(\"<%= Ti_Platform_name %>\"===couldBeAnything())var a=1;else var a=2"],
	["if (Ti.Platform.name === some.Other.Value) { var a = 1; } else { var a = 2; }","if(\"<%= Ti_Platform_name %>\"===some.Other.Value)var a=1;else var a=2"],
	["if (Ti.Platform.name !== aVariable) { var a = 1; } else { var a = 2; }","if(\"<%= Ti_Platform_name %>\"!==aVariable)var a=1;else var a=2"],

	// properly handles conditionals without curly braces
	["if (Ti.Platform.name === '<%= Ti_Platform_name %>') var a = 1; else var a = 2;","var a=1"],
	["if (Ti.Platform.name !== '<%= Ti_Platform_name %>') var a = 1; else var a = 2;","var a=2"],
	["if ('<%= Ti_Platform_name %>' === Ti.Platform.name) var a = 1; else var a = 2;","var a=1"],
	["if ('<%= Ti_Platform_name %>' !== Ti.Platform.name) var a = 1; else var a = 2;","var a=2"],

	// works if Ti.Platform.* is on the left or right hand side
	["if ('<%= Ti_Platform_name %>' === Ti.Platform.name) { var a = 1; } else { a = 2; }","var a=1"],
];

// Prepare each platform with values we can swap out at compile time.
// This means less walks over the native bridge, which means better performance.
// Using underscores in the key names since underscore template()
// chokes when there's periods in the key name.
var platforms = {
	android: {
		'Ti_Platform_name': 'android',
		'Ti_Platform_osname': 'android'
	},
	ios: {
		'Ti_Platform_name': 'iPhone OS',
		'Ti_Platform_osname': ['ipad','iphone']
	},
	mobileweb: {
		'Ti_Platform_name': 'mobileweb',
		'Ti_Platform_osname': 'mobileweb'
	}
};
_.each(platforms, function(obj,p) {
	_.each(obj, function(v,k) {
		platforms[p][k.replace('Ti_','Titanium_')] = v;
	});
});

// The alloy command test suite
describe('optimizer.js', function() {
	_.each(tests, function(test, index) {
		describe('test #' + (index+1), function() {
			_.each(platforms, function(platformObj, platform) {
				describe('[' + platform + ']', function() {
					var ast, code,
						testContent = _.template(test[0], platforms[platform]),
						prefix = pad(platform),
						defines = {
							OS_ANDROID: platform === 'android',
							OS_IOS: platform === 'ios',
							OS_MOBILEWEB: platform === 'mobileweb'
						};

					it(prefix + testContent.blue, function() {
						expect(true).toBe(true);
					});

					it(prefix + 'parses AST with uglifyjs', function() {
						var parseFunction = function() {
							ast = uglifyjs.parse(testContent);
						};
						expect(parseFunction).not.toThrow();
					});

					it(prefix + 'optimizes AST via optimizer.js', function() {
						var optimizeFunction = function() {
							ast.figure_out_scope();
							ast = optimizer.optimize(ast, defines);
						};
						expect(optimizeFunction).not.toThrow();
					});

					it(prefix + 'ast_squeeze', function() {
						// execute the squeeze to remove dead code, always performed
						// as the last step of JS file processing. The unit testing here
						// uses the same settings as the Alloy compile process.
						var squeezeFunction = function() {
							var options = {
								sequences     : true,  // join consecutive statemets with the “comma operator”
								properties    : false,   // optimize property access: a["foo"] → a.foo
								dead_code     : true,   // discard unreachable code
								drop_debugger : false,   // discard “debugger” statements
								unsafe        : false,   // some unsafe optimizations (see below)
								conditionals  : true,   // optimize if-s and conditional expressions
								comparisons   : true,   // optimize comparisons
								evaluate      : true,   // evaluate constant expressions
								booleans      : true,   // optimize boolean expressions
								loops         : false,   // optimize loops
								unused        : true,   // drop unused variables/functions
								hoist_funs    : true,   // hoist function declarations
								hoist_vars    : false,  // hoist variable declarations
								if_return     : true,   // optimize if-s followed by return/continue
								join_vars     : true,   // join var declarations
								cascade       : true,   // try to cascade `right` into `left` in sequences
								side_effects  : true,   // drop side-effect-free statements
								warnings      : false,   // warn about potentially dangerous optimizations/code
								global_defs   : defines      // global definitions
							};

							ast.figure_out_scope();
							ast = ast.transform(uglifyjs.Compressor(options));
						};
						expect(squeezeFunction).not.toThrow();
					});

					it(prefix + 'generates code from optimized AST via uglifyjs', function() {
						var generateFunction = function() {
							var stream = uglifyjs.OutputStream({
								beautify: false,
								semicolons: false,
								bracketize: false
							});
							ast.print(stream);
							code = stream.toString().replace(/\s*$/,'');
						};
						expect(generateFunction).not.toThrow();
					});

					it(prefix + 'generated code matches expected code', function() {
						var passFor = test[2];
						var expected = _.template(test[1], platforms[platform]);

						if (!passFor || _.contains(passFor, platform)) {
							expect(code).toBe(expected);
						} else {
							expect(code).not.toBe(expected);
						}
					});
				});
			});
		});
	});
});

// helper functions
function notPlatform(platform) {
	return _.reject(CONST.PLATFORMS, function(p) { return p === platform; } );
}

function pad(string) {
	var ret = '';
	for (var i = 0; i < 10 - string.length; i++) {
		ret += ' ';
	}
	return ret;
}

<commit_msg>modified a handful of optimizations unit tests to conform to uglify-js v2 compression (ALOY-558)<commit_after>var fs = require('fs'),
	path = require('path'),
	colors = require('colors'),
	TU = require('../lib/testUtils'),
	CONST = require('../../Alloy/common/constants'),
	_ = require('../../Alloy/lib/alloy/underscore')._,
	uglifyjs = require('uglify-js'),
	optimizer = require('../../Alloy/commands/compile/optimizer');

var tests = [
	// make sure we didn't break normal conditionals and assigments
	['var a = Ti.Platform.name', 'var a="<%= Ti_Platform_name %>"'],
	['var a = Titanium.Platform.name', 'var a="<%= Titanium_Platform_name %>"'],
	['var a = Ti.Platform.name=="<%= Titanium_Platform_name %>" ? 1 : 0', 'var a=1'],
	['var a = Ti.Platform.name=="<%= Titanium_Platform_name %>", b', 'var a=!0,b'],
	['var a = Ti.Platform.name=="<%= Titanium_Platform_name %>", b, c = 2', 'var a=!0,b,c=2'],
	['var a = Ti.Platform.name=="<%= Titanium_Platform_name %>"', 'var a=!0'],
	['var a = Ti.Platform.name!="iPhone OS"', 'var a=!1', ['ios']],
	['var a = Ti.Platform.name=="iPhone OS"', 'var a=!1', notPlatform('ios')],
	['var a, b = Ti.Platform.name=="<%= Titanium_Platform_name %>", c = 2;', 'var a,b=!0,c=2'],
	['var a = "<%= Titanium_Platform_name %>"==Ti.Platform.name ? 1 : 0', 'var a=1'],
	['var a = "<%= Titanium_Platform_name %>"==Ti.Platform.name, b', 'var a=!0,b'],
	['var a = "<%= Titanium_Platform_name %>"==Ti.Platform.name, b, c = 2', 'var a=!0,b,c=2'],
	['var a = "<%= Titanium_Platform_name %>"==Ti.Platform.name', 'var a=!0'],
	['var a = "iPhone OS"!=Ti.Platform.name', 'var a=!1', ['ios']],
	['var a = "iPhone OS"==Ti.Platform.name', 'var a=!1', notPlatform('ios')],
	['var a, b = "<%= Titanium_Platform_name %>"==Ti.Platform.name, c = 2;', 'var a,b=!0,c=2'],
	['var a = "1"', 'var a="1"'],
	['var a = true', 'var a=!0'],
	['var a = 1', 'var a=1'],
	['var a', 'var a'],
	['var a = {}', 'var a={}'],
	['var a = new Object', 'var a=new Object'],
	['var a = new Object()', 'var a=new Object'],
	['var a = Ti.Platform.name', 'var a="<%= Ti_Platform_name %>"'],
	['var a = Ti.Platform.osname', 'var a="android"', ['android']],
	['var a = Ti.Platform.osname', 'var a="mobileweb"', ['mobileweb']],
	['var a, b = 1, c = 2;', 'var a,b=1,c=2'],
	['var a = 1;', 'var a=1'],
	['var a =+1;', 'var a=1'],
	['var a =1+1;', 'var a=2'],
	['var a = 1.0;', 'var a=1'],
	['var a = 1.02;', 'var a=1.02'],
	['var a = -1.02;', 'var a=-1.02'],
	['var a = !1', 'var a=!1'],
	['var a = true ? 1 : 0;', 'var a=1'],
	["var num = isNaN(amount) || amount === '' || amount === null ? 0.00 : amount;", 'var num=isNaN(amount)||""===amount||null===amount?0:amount'],

	// make sure we didn't break normal if conditions
	['if (true) { var a = 1; } else { var a = 2; }', "var a=1"],

	// check platform conditionals (if/else)
	["if (Titanium.Platform.name === '<%= Titanium_Platform_name %>'){ var a = 1; } else { var a = 2; }","var a=1"],
	["if (Titanium.Platform.name !== '<%= Titanium_Platform_name %>'){ var a = 1; } else { var a = 2; }","var a=2"],
	["if (Titanium.Platform['name'] == '<%= Titanium_Platform_name %>'){ var a = 1; } else { var a = 2; }","var a=1"],
	["if (Titanium.Platform.name !== '<%= Titanium_Platform_name %>'){ var a = 1; } else { var a = 2; }","var a=2"],
	["if (Titanium.Platform['name'] !== '<%= Titanium_Platform_name %>'){ var a = 1; } else { var a = 2; }","var a=2"],

	// check platform conditional assignments
	["var platform = Ti.Platform['name'] === '<%= Ti_Platform_name %>'", "var platform=!0"],
	["var platform = Ti.Platform[\"name\"] === '<%= Ti_Platform_name %>'", "var platform=!0"],
	["var platform = Ti.Platform.name === '<%= Ti_Platform_name %>'", "var platform=!0"],
	["var platform = Ti.Platform.name === 'iPhone OS'", "var platform=!1", notPlatform('ios')],
	["var platform = (Ti.Platform.name === '<%= Ti_Platform_name %>')", "var platform=!0"],
	["var platform = (Ti.Platform.name === '<%= Ti_Platform_name %>') ? 1 : 0", "var platform=1"],
	["var platform = (Ti.Platform.name === '<%= Ti_Platform_name %>') ? true : false", "var platform=!0"],
	["var platform = (Ti.Platform.name === 'iPhone OS') ? 1 : 0", "var platform=0", notPlatform('ios')],
	["var platform = (Ti.Platform.name === 'iPhone OS') ? true : false", "var platform=!1", notPlatform('ios')],
	["var platform = (Ti.Platform.name == '<%= Ti_Platform_name %>') ? 'true' : 'false'", "var platform=\"true\""],
	["var platform = (Ti.Platform.name == 'iPhone OS') ? 'true' : 'false'", "var platform=\"false\"", notPlatform('ios')],
	["var platform = (Ti.Platform.osname == 'android') ? 'true' : 'false'", "var platform=\"true\"", ['android']],
	["var platform = (Ti.Platform.osname == \"iphone\") ? 1 : 0", "var platform=0", notPlatform('ios')],
	["var platform = (Ti.Platform.osname == \"iphone\") ? 1 : 0", "var platform=\"iphone\"==Ti.Platform.osname?1:0", ['ios']],

	// check identities
	["var a = Ti.Platform.name === Titanium.Platform.name","var a=!0"],

	// shouldn't attempt to process anything other than strings
	["if (Ti.Platform.name === couldBeAnything()) { var a = 1; } else { var a = 2; }","if(\"<%= Ti_Platform_name %>\"===couldBeAnything())var a=1\nelse var a=2"],
	["if (Ti.Platform.name === some.Other.Value) { var a = 1; } else { var a = 2; }","if(\"<%= Ti_Platform_name %>\"===some.Other.Value)var a=1\nelse var a=2"],
	["if (Ti.Platform.name !== aVariable) { var a = 1; } else { var a = 2; }","if(\"<%= Ti_Platform_name %>\"!==aVariable)var a=1\nelse var a=2"],

	// properly handles conditionals without curly braces
	["if (Ti.Platform.name === '<%= Ti_Platform_name %>') var a = 1; else var a = 2;","var a=1"],
	["if (Ti.Platform.name !== '<%= Ti_Platform_name %>') var a = 1; else var a = 2;","var a=2"],
	["if ('<%= Ti_Platform_name %>' === Ti.Platform.name) var a = 1; else var a = 2;","var a=1"],
	["if ('<%= Ti_Platform_name %>' !== Ti.Platform.name) var a = 1; else var a = 2;","var a=2"],

	// works if Ti.Platform.* is on the left or right hand side
	["if ('<%= Ti_Platform_name %>' === Ti.Platform.name) { var a = 1; } else { a = 2; }","var a=1"],
];

// Prepare each platform with values we can swap out at compile time.
// This means less walks over the native bridge, which means better performance.
// Using underscores in the key names since underscore template()
// chokes when there's periods in the key name.
var platforms = {
	android: {
		'Ti_Platform_name': 'android',
		'Ti_Platform_osname': 'android'
	},
	ios: {
		'Ti_Platform_name': 'iPhone OS',
		'Ti_Platform_osname': ['ipad','iphone']
	},
	mobileweb: {
		'Ti_Platform_name': 'mobileweb',
		'Ti_Platform_osname': 'mobileweb'
	}
};
_.each(platforms, function(obj,p) {
	_.each(obj, function(v,k) {
		platforms[p][k.replace('Ti_','Titanium_')] = v;
	});
});

// The alloy command test suite
describe('optimizer.js', function() {
	_.each(tests, function(test, index) {
		describe('test #' + (index+1), function() {
			_.each(platforms, function(platformObj, platform) {
				describe('[' + platform + ']', function() {
					var ast, code,
						testContent = _.template(test[0], platforms[platform]),
						prefix = pad(platform),
						defines = {
							OS_ANDROID: platform === 'android',
							OS_IOS: platform === 'ios',
							OS_MOBILEWEB: platform === 'mobileweb'
						};

					it(prefix + testContent.blue, function() {
						expect(true).toBe(true);
					});

					it(prefix + 'parses AST with uglifyjs', function() {
						var parseFunction = function() {
							ast = uglifyjs.parse(testContent);
						};
						expect(parseFunction).not.toThrow();
					});

					it(prefix + 'optimizes AST via optimizer.js', function() {
						var optimizeFunction = function() {
							ast.figure_out_scope();
							ast = optimizer.optimize(ast, defines);
						};
						expect(optimizeFunction).not.toThrow();
					});

					it(prefix + 'ast_squeeze', function() {
						// execute the squeeze to remove dead code, always performed
						// as the last step of JS file processing. The unit testing here
						// uses the same settings as the Alloy compile process.
						var squeezeFunction = function() {
							var options = {
								sequences     : true,  // join consecutive statemets with the “comma operator”
								properties    : false,   // optimize property access: a["foo"] → a.foo
								dead_code     : true,   // discard unreachable code
								drop_debugger : false,   // discard “debugger” statements
								unsafe        : false,   // some unsafe optimizations (see below)
								conditionals  : true,   // optimize if-s and conditional expressions
								comparisons   : true,   // optimize comparisons
								evaluate      : true,   // evaluate constant expressions
								booleans      : true,   // optimize boolean expressions
								loops         : false,   // optimize loops
								unused        : true,   // drop unused variables/functions
								hoist_funs    : true,   // hoist function declarations
								hoist_vars    : false,  // hoist variable declarations
								if_return     : true,   // optimize if-s followed by return/continue
								join_vars     : true,   // join var declarations
								cascade       : true,   // try to cascade `right` into `left` in sequences
								side_effects  : true,   // drop side-effect-free statements
								warnings      : false,   // warn about potentially dangerous optimizations/code
								global_defs   : defines      // global definitions
							};

							ast.figure_out_scope();
							ast = ast.transform(uglifyjs.Compressor(options));
						};
						expect(squeezeFunction).not.toThrow();
					});

					it(prefix + 'generates code from optimized AST via uglifyjs', function() {
						var generateFunction = function() {
							var stream = uglifyjs.OutputStream({
								beautify: false,
								semicolons: false,
								bracketize: false
							});
							ast.print(stream);
							code = stream.toString().replace(/\s*$/,'');
						};
						expect(generateFunction).not.toThrow();
					});

					it(prefix + 'generated code matches expected code', function() {
						var passFor = test[2];
						var expected = _.template(test[1], platforms[platform]);

						if (!passFor || _.contains(passFor, platform)) {
							expect(code).toBe(expected);
						} else {
							expect(code).not.toBe(expected);
						}
					});
				});
			});
		});
	});
});

// helper functions
function notPlatform(platform) {
	return _.reject(CONST.PLATFORMS, function(p) { return p === platform; } );
}

function pad(string) {
	var ret = '';
	for (var i = 0; i < 10 - string.length; i++) {
		ret += ' ';
	}
	return ret;
}

<|endoftext|>


<commit_before>var fs = require('fs'),
    path = require('path'),
    crypto = require('crypto'),
    extend = require('soak').mixin,
    inherit = require('soak').inherit,
    EventEmitter = require('events').EventEmitter;

module.exports = {
  // Create a base observable object that inherits from EventEmitter. This
  // allows us to create new objects that can trigger events very easily.
  //
  // Example:
  //
  //   var Store = Observable.extend({
  //     save: function () {}
  //   });
  Observable: inherit(EventEmitter),

  // Helper function for creating an index file in a directory. It loads all
  // modules within the provided directory excluding the file provided as
  // "indexpath". These will then be returned.
  //
  // Example:
  //
  //   module.exports = utils.index(__dirname, __filename);
  index: function (dirname, indexpath) {
    var extensions = {js: 1},
        modules = {};

    indexpath = indexpath || path.join(dirname, 'index.js');

    // Load all exported objects into a single module.
    fs.readdirSync(dirname).forEach(function (filename) {
      var fullpath = path.join(dirname, filename),
          parts    = filename.split('.'),
          module, name;

      if (fullpath !== indexpath && extensions[parts.pop()] && '.' !== filename[0]) {
        name = parts.join('.');
        module = require(fullpath);

        // Grab the function name or module name if possible.
        if (typeof module.name === 'string') {
          name = module.name;
        }

        modules[name] = module;
      }
    });

    return modules;
  },

  // Takes an object and a series of method names. Each method will be
  // re-assigned to the object with the object bound as the methods scope. This
  // is generally useful for defining callback methods.
  //
  // An array of method names can also be passed.
  //
  // Example:
  //
  //   object = {onData: function () {}, onEnd: function () {});
  //   utils.bindAll(object, 'onData', 'onEnd');
  //
  //   // Same as doing.
  //   object.onData = object.onData.bind(object);
  //   object.onEnd  = object.onEnd.bind(object);
  bindAll: function (object /* args */) {
    var methods = [].slice.call(arguments, 1);
    if (arguments.length === 2 && Array.isArray(arguments[1])) {
      methods = arguments[1];
    }

    methods.forEach(function (method) {
      if (typeof object[method] === 'function') {
        object[method] = object[method].bind(object);
      }
    });

    return object;
  },

  // Extends the first argument with the properties of the subsequent
  // arguments.
  extend: extend,

  // Simplifies the process of extending existing objects.
  inherit: inherit,

  extract: function (obj /* keys */) {
    var keys = [].slice.call(arguments, 1),
        collected = {};

    keys.forEach(function (key) {
      if (obj[key]) {
        collected[key] = obj[key];
      }
    });

    return collected;
  },
  isAjax: function (req) {
    return (req.get('X-Requested-With') || '').toLowerCase() === 'xmlhttprequest';
  },
  shortcode: function () {
    var vowels = 'aeiou',
        consonants = 'bcdfghjklmnpqrstvwxyz',
        word = '', length = 6, index = 0, set;

    for (; index < length; index += 1) {
      set = (index % 2 === 0) ? vowels : consonants;
      word += set[Math.floor(Math.random() * set.length)];
    }

    return word;
  },
  // Returns a gravatar url for the email address provided. An optional size
  // parameter can be provided to specify the size of the avatar to generate.
  gravatar: function (email, size) {
    email = (email || '').trim().toLowerCase();
    var hash = crypto.createHash('md5').update(email).digest('hex');
    return 'http://www.gravatar.com/avatar/' + hash + '?s=' + (size || 26);
  },
  re: {
    flatten: /\s+/g,
    body: /<body.*?>\s*(.*)/m,
    meta: /<meta name="description" content="(.*?)"/,
    tags: /<[^>]+>/g,
    title: /<title>(.*)<\/title>/
  },
  titleForBin: function (bin) {
    var html = (bin.html || '').replace(this.re.flatten, ' '), // flatten
        javascript = (bin.javascript || '').replace(this.re.flatten, ' ').trim(),
        css = (bin.css || '').replace(this.re.flatten, ' ').trim(),
        matches = (html.match(this.re.meta) || []);

    // try to return the meta[description] first
    if (matches.length === 2 && matches[1].trim()) {
      return matches[1];
    }

    // then some of the body content with tags stripped
    matches = (html.match(this.re.body) || ['', ''])[1].replace(this.re.tags, '').trim();

    if (matches) {
      return matches;
    }

    // No title return JavaScript.
    if (javascript) {
      return javascript;
    }

    if (css) {
      return css;
    }

    matches = (html.match(this.re.title) || []);
    if (matches.length === 2 && matches[1].trim()) {
      return matches[1];
    }

    return html.replace(this.re.tags, '').trim();
  },
  since: function (date) {
    var diff    = (+new Date() - date) / 1000,
        message = 'a long time',
        timespan;

    if (diff < 60) {
      timespan = Math.floor(diff);
      message  = '{timespan} second';
    }
    else if (diff < 3600) {
      timespan =  Math.floor(diff / 60);
      message  = 'about {timespan} minute';
    }
    else if (diff < 86400) {
      timespan = Math.floor(diff / 3600);
      message  = 'around {timespan} hour';
    }
    else if (diff < 604800) {
      timespan = Math.floor(diff / 86400);
      message  = 'about {timespan} day';
    }
    else if (diff < 2419200) {
      timespan = Math.ceil(diff / 604800);
      message  = 'nearly {timespan} week';
    }
    else if (diff < 29030400) {
      timespan = Math.floor(diff / 2419200);
      message  = 'about {timespan} month';
    }

    if (timespan !== 1 && timespan) {
      message += 's';
    }

    return message.replace('{timespan}', timespan) + ' ago';
  },
  queryStringForBin: function (bin, defaults) {
    var params = [];
    ['html', 'javascript', 'css'].forEach(function (key) {
      if (bin[key]) {
        params.push(key);
      }
    });
    params.push('live');
    return params.join(',');
  },
  cleanForRender: function (str) {
    var cache = {
      '\u2028': '
',
      '\u2029': '
'
    };

    var re, bad;

    for (bad in cache) {
      if (str.indexOf(bad) != -1) {
        re = new RegExp(bad, 'g');
        str = str.replace(re, cache[bad]);
      }
    }

    return str;
  }
};
<commit_msg>Display date not 'a long time ago' on home list.<commit_after>var fs = require('fs'),
    path = require('path'),
    crypto = require('crypto'),
    extend = require('soak').mixin,
    inherit = require('soak').inherit,
    EventEmitter = require('events').EventEmitter;

module.exports = {
  // Create a base observable object that inherits from EventEmitter. This
  // allows us to create new objects that can trigger events very easily.
  //
  // Example:
  //
  //   var Store = Observable.extend({
  //     save: function () {}
  //   });
  Observable: inherit(EventEmitter),

  // Helper function for creating an index file in a directory. It loads all
  // modules within the provided directory excluding the file provided as
  // "indexpath". These will then be returned.
  //
  // Example:
  //
  //   module.exports = utils.index(__dirname, __filename);
  index: function (dirname, indexpath) {
    var extensions = {js: 1},
        modules = {};

    indexpath = indexpath || path.join(dirname, 'index.js');

    // Load all exported objects into a single module.
    fs.readdirSync(dirname).forEach(function (filename) {
      var fullpath = path.join(dirname, filename),
          parts    = filename.split('.'),
          module, name;

      if (fullpath !== indexpath && extensions[parts.pop()] && '.' !== filename[0]) {
        name = parts.join('.');
        module = require(fullpath);

        // Grab the function name or module name if possible.
        if (typeof module.name === 'string') {
          name = module.name;
        }

        modules[name] = module;
      }
    });

    return modules;
  },

  // Takes an object and a series of method names. Each method will be
  // re-assigned to the object with the object bound as the methods scope. This
  // is generally useful for defining callback methods.
  //
  // An array of method names can also be passed.
  //
  // Example:
  //
  //   object = {onData: function () {}, onEnd: function () {});
  //   utils.bindAll(object, 'onData', 'onEnd');
  //
  //   // Same as doing.
  //   object.onData = object.onData.bind(object);
  //   object.onEnd  = object.onEnd.bind(object);
  bindAll: function (object /* args */) {
    var methods = [].slice.call(arguments, 1);
    if (arguments.length === 2 && Array.isArray(arguments[1])) {
      methods = arguments[1];
    }

    methods.forEach(function (method) {
      if (typeof object[method] === 'function') {
        object[method] = object[method].bind(object);
      }
    });

    return object;
  },

  // Extends the first argument with the properties of the subsequent
  // arguments.
  extend: extend,

  // Simplifies the process of extending existing objects.
  inherit: inherit,

  extract: function (obj /* keys */) {
    var keys = [].slice.call(arguments, 1),
        collected = {};

    keys.forEach(function (key) {
      if (obj[key]) {
        collected[key] = obj[key];
      }
    });

    return collected;
  },
  isAjax: function (req) {
    return (req.get('X-Requested-With') || '').toLowerCase() === 'xmlhttprequest';
  },
  shortcode: function () {
    var vowels = 'aeiou',
        consonants = 'bcdfghjklmnpqrstvwxyz',
        word = '', length = 6, index = 0, set;

    for (; index < length; index += 1) {
      set = (index % 2 === 0) ? vowels : consonants;
      word += set[Math.floor(Math.random() * set.length)];
    }

    return word;
  },
  // Returns a gravatar url for the email address provided. An optional size
  // parameter can be provided to specify the size of the avatar to generate.
  gravatar: function (email, size) {
    email = (email || '').trim().toLowerCase();
    var hash = crypto.createHash('md5').update(email).digest('hex');
    return 'http://www.gravatar.com/avatar/' + hash + '?s=' + (size || 26);
  },
  re: {
    flatten: /\s+/g,
    body: /<body.*?>\s*(.*)/m,
    meta: /<meta name="description" content="(.*?)"/,
    tags: /<[^>]+>/g,
    title: /<title>(.*)<\/title>/
  },
  titleForBin: function (bin) {
    var html = (bin.html || '').replace(this.re.flatten, ' '), // flatten
        javascript = (bin.javascript || '').replace(this.re.flatten, ' ').trim(),
        css = (bin.css || '').replace(this.re.flatten, ' ').trim(),
        matches = (html.match(this.re.meta) || []);

    // try to return the meta[description] first
    if (matches.length === 2 && matches[1].trim()) {
      return matches[1];
    }

    // then some of the body content with tags stripped
    matches = (html.match(this.re.body) || ['', ''])[1].replace(this.re.tags, '').trim();

    if (matches) {
      return matches;
    }

    // No title return JavaScript.
    if (javascript) {
      return javascript;
    }

    if (css) {
      return css;
    }

    matches = (html.match(this.re.title) || []);
    if (matches.length === 2 && matches[1].trim()) {
      return matches[1];
    }

    return html.replace(this.re.tags, '').trim();
  },
  since: function (date) {
    var diff    = (+new Date() - date) / 1000,
        message = 'a long time',
        timespan;

    try {
      // make "Thu Jan 10 2013 16:32:37 GMT+0000 (GMT)" into "10 Jan 2013"
      var parts = date.toString().split(' ').slice(1,4);
      message = parts.slice(2).concat(parts.slice(0,2)).reverse().join(' ');
    } catch(e) {}

    if (diff < 60) {
      timespan = Math.floor(diff);
      message  = '{timespan} second';
    }
    else if (diff < 3600) {
      timespan =  Math.floor(diff / 60);
      message  = 'about {timespan} minute';
    }
    else if (diff < 86400) {
      timespan = Math.floor(diff / 3600);
      message  = 'around {timespan} hour';
    }
    else if (diff < 604800) {
      timespan = Math.floor(diff / 86400);
      message  = 'about {timespan} day';
    }
    else if (diff < 2419200) {
      timespan = Math.ceil(diff / 604800);
      message  = 'nearly {timespan} week';
    }
    else if (diff < 29030400) {
      timespan = Math.floor(diff / 2419200);
      message  = 'about {timespan} month';
    }

    if (timespan !== 1 && timespan) {
      message += 's';
      return message.replace('{timespan}', timespan) + ' ago';
    } else {
      return message;
    }
  },
  queryStringForBin: function (bin, defaults) {
    var params = [];
    ['html', 'javascript', 'css'].forEach(function (key) {
      if (bin[key]) {
        params.push(key);
      }
    });
    params.push('live');
    return params.join(',');
  },
  cleanForRender: function (str) {
    var cache = {
      '\u2028': '
',
      '\u2029': '
'
    };

    var re, bad;

    for (bad in cache) {
      if (str.indexOf(bad) != -1) {
        re = new RegExp(bad, 'g');
        str = str.replace(re, cache[bad]);
      }
    }

    return str;
  }
};
<|endoftext|>


<commit_before>var fs = require('fs'),
    path = require('path'),
    hbs = require('handlebars'),
    helpers = require('../lib/helpers')(hbs),
    Promise = require('promise'),
    admzip = require('adm-zip'),
    temp = require('temp').track(),
    sqlite3 = require('sqlite3').verbose();

module.exports.buildDashDocSet = function (input) {

    return new Promise(function (resolve) {

        var zip = new admzip(),
            tempdb = temp.openSync('temp.sqlite'),
            db = new sqlite3.Database(tempdb.path);

        input.uid = module.exports.formatStringForUID(input.title);

        input.files.forEach(function (file) {

            file.methods.forEach(function (method) {

                if (!method.ignore && method.ctx) {

                    zip.addFile(
                        input.title + '.docset/Contents/Resources/Documents/' + method.ctx.uid + '.html',
                        require('../templates/dash/index.hbs')(method)
                    );

                }

            });

        });

        zip.addFile(
            input.title + '.docset/Contents/Info.plist',
            require('../templates/dash/plist.hbs')(input)
        );

        [
            'bootstrap/bootstrap.min.css',
            'highlight.js/github.min.css'
        ].forEach(function (resource) {

            zip.addLocalFile(
                path.join(__dirname, '../templates/dash/resources/' + resource),
                input.title + '.docset/Contents/Resources/Documents/resources/' + path.dirname(resource)
            );

        });

        db.serialize(function () {

            db.run('CREATE TABLE searchIndex(id INTEGER PRIMARY KEY, name TEXT, type TEXT, path TEXT);');
            db.run('CREATE UNIQUE INDEX anchor ON searchIndex (name, type, path);');

            input.files.forEach(function (file) {

                file.methods.forEach(function (method) {

                    if (!method.ignore && method.ctx) {

                        db.run('INSERT OR IGNORE INTO searchIndex(name, type, path) VALUES ($name, $type, $path);', {
                            $name: hbs.helpers.formatName(method.ctx.string),
                            $type: method.ctx.type.replace(/^[a-z]/, function (match) { return match.toUpperCase(); }),
                            $path: method.ctx.uid + '.html'
                        });

                    }

                });

            });

        });

        db.close(function () {

            zip.addFile(
                input.title + '.docset/Contents/Resources/docSet.dsidx',
                fs.readFileSync(tempdb.path)
            );

            resolve(zip.toBuffer());

        });

    });

};

module.exports.findPackage = function (input) {

    var pkg,
        stat;

    if (fs.existsSync(input)) {

        stat = fs.statSync(input);

        if (stat.isDirectory()) {

            pkg = path.normalize(path.resolve(input) + '/package.json');

        } else if (stat.isFile()) {

            pkg = path.normalize(path.resolve(path.dirname(input)) + '/package.json');

        }

    }

    return pkg;

};

module.exports.formatStringForUID = function (content) {

    content = String(content).toLowerCase();

    content = content.replace(/[^\w\.]+/g, '-');
    content = content.replace(/^-|-$/g, '');

    return content;

};

module.exports.parseData = function (data, file) {

    data.forEach(function (methods) {

        if (methods.ctx) {

            methods.ctx.uid = file + '-' + module.exports.formatStringForUID(methods.ctx.string);

        }

        if (methods.tags) {

            methods.tags.forEach(function (tag) {

                if (tag.types) {

                    tag.types.forEach(function (type, index) {

                        if (type.match(/\?/g)) {

                            tag.types[index] = type.replace(/\?/g, '');

                        }

                    });

                }

            });

        }

    });

    return data;

};

module.exports.walk = function (dir, options) {

    var files = [];

    if (!options) {

        options = {};

    }

    if (!options.match) {

        options.match = /\.js$/;

    }

    if (!options.exception) {

        options.exception = /\.git|\.min|node_modules|bower_components|test|gruntfile|gulpfile/i;

    }

    if (fs.existsSync(dir) && fs.statSync(dir).isDirectory()) {

        fs.readdirSync(dir).forEach(function (file) {

            var stat;

            file = path.normalize(dir + '/' + file);

            stat = fs.statSync(file);

            if (stat.isDirectory() && !file.match(options.exception)) {

                files = files.concat(module.exports.walk(file, options));

            } else if (stat.isFile() && file.match(options.match) && !file.match(options.exception)) {

                files.push(file);

            }

        });

    }

    return files;

};
<commit_msg>Removed brackets from around optional tag names.<commit_after>var fs = require('fs'),
    path = require('path'),
    hbs = require('handlebars'),
    helpers = require('../lib/helpers')(hbs),
    Promise = require('promise'),
    admzip = require('adm-zip'),
    temp = require('temp').track(),
    sqlite3 = require('sqlite3').verbose();

module.exports.buildDashDocSet = function (input) {

    return new Promise(function (resolve) {

        var zip = new admzip(),
            tempdb = temp.openSync('temp.sqlite'),
            db = new sqlite3.Database(tempdb.path);

        input.uid = module.exports.formatStringForUID(input.title);

        input.files.forEach(function (file) {

            file.methods.forEach(function (method) {

                if (!method.ignore && method.ctx) {

                    zip.addFile(
                        input.title + '.docset/Contents/Resources/Documents/' + method.ctx.uid + '.html',
                        require('../templates/dash/index.hbs')(method)
                    );

                }

            });

        });

        zip.addFile(
            input.title + '.docset/Contents/Info.plist',
            require('../templates/dash/plist.hbs')(input)
        );

        [
            'bootstrap/bootstrap.min.css',
            'highlight.js/github.min.css'
        ].forEach(function (resource) {

            zip.addLocalFile(
                path.join(__dirname, '../templates/dash/resources/' + resource),
                input.title + '.docset/Contents/Resources/Documents/resources/' + path.dirname(resource)
            );

        });

        db.serialize(function () {

            db.run('CREATE TABLE searchIndex(id INTEGER PRIMARY KEY, name TEXT, type TEXT, path TEXT);');
            db.run('CREATE UNIQUE INDEX anchor ON searchIndex (name, type, path);');

            input.files.forEach(function (file) {

                file.methods.forEach(function (method) {

                    if (!method.ignore && method.ctx) {

                        db.run('INSERT OR IGNORE INTO searchIndex(name, type, path) VALUES ($name, $type, $path);', {
                            $name: hbs.helpers.formatName(method.ctx.string),
                            $type: method.ctx.type.replace(/^[a-z]/, function (match) { return match.toUpperCase(); }),
                            $path: method.ctx.uid + '.html'
                        });

                    }

                });

            });

        });

        db.close(function () {

            zip.addFile(
                input.title + '.docset/Contents/Resources/docSet.dsidx',
                fs.readFileSync(tempdb.path)
            );

            resolve(zip.toBuffer());

        });

    });

};

module.exports.findPackage = function (input) {

    var pkg,
        stat;

    if (fs.existsSync(input)) {

        stat = fs.statSync(input);

        if (stat.isDirectory()) {

            pkg = path.normalize(path.resolve(input) + '/package.json');

        } else if (stat.isFile()) {

            pkg = path.normalize(path.resolve(path.dirname(input)) + '/package.json');

        }

    }

    return pkg;

};

module.exports.formatStringForUID = function (content) {

    content = String(content).toLowerCase();

    content = content.replace(/[^\w\.]+/g, '-');
    content = content.replace(/^-|-$/g, '');

    return content;

};

module.exports.parseData = function (data, file) {

    data.forEach(function (methods) {

        if (methods.ctx) {

            methods.ctx.uid = file + '-' + module.exports.formatStringForUID(methods.ctx.string);

        }

        if (methods.tags) {

            methods.tags.forEach(function (tag) {

                if (tag.name && tag.optional) {

                    tag.name = tag.name.replace(/^\[|\]$/g, '');

                }

            });

        }

    });

    return data;

};

module.exports.walk = function (dir, options) {

    var files = [];

    if (!options) {

        options = {};

    }

    if (!options.match) {

        options.match = /\.js$/;

    }

    if (!options.exception) {

        options.exception = /\.git|\.min|node_modules|bower_components|test|gruntfile|gulpfile/i;

    }

    if (fs.existsSync(dir) && fs.statSync(dir).isDirectory()) {

        fs.readdirSync(dir).forEach(function (file) {

            var stat;

            file = path.normalize(dir + '/' + file);

            stat = fs.statSync(file);

            if (stat.isDirectory() && !file.match(options.exception)) {

                files = files.concat(module.exports.walk(file, options));

            } else if (stat.isFile() && file.match(options.match) && !file.match(options.exception)) {

                files.push(file);

            }

        });

    }

    return files;

};
<|endoftext|>


<commit_before>'use strict';

var bind = require('./helpers/bind');

// utils is a library of generic helper functions non-specific to axios

var toString = Object.prototype.toString;

// eslint-disable-next-line func-names
var kindOf = (function(cache) {
  // eslint-disable-next-line func-names
  return function(thing) {
    var str = toString.call(thing);
    return cache[str] || (cache[str] = str.slice(8, -1).toLowerCase());
  };
})(Object.create(null));

function kindOfTest(type) {
  type = type.toLowerCase();
  return function isKindOf(thing) {
    return kindOf(thing) === type;
  };
}

/**
 * Determine if a value is an Array
 *
 * @param {Object} val The value to test
 * @returns {boolean} True if value is an Array, otherwise false
 */
function isArray(val) {
  return Array.isArray(val);
}

/**
 * Determine if a value is undefined
 *
 * @param {Object} val The value to test
 * @returns {boolean} True if the value is undefined, otherwise false
 */
function isUndefined(val) {
  return typeof val === 'undefined';
}

/**
 * Determine if a value is a Buffer
 *
 * @param {Object} val The value to test
 * @returns {boolean} True if value is a Buffer, otherwise false
 */
function isBuffer(val) {
  return val !== null && !isUndefined(val) && val.constructor !== null && !isUndefined(val.constructor)
    && typeof val.constructor.isBuffer === 'function' && val.constructor.isBuffer(val);
}

/**
 * Determine if a value is an ArrayBuffer
 *
 * @function
 * @param {Object} val The value to test
 * @returns {boolean} True if value is an ArrayBuffer, otherwise false
 */
var isArrayBuffer = kindOfTest('ArrayBuffer');

/**
 * Determine if a value is a view on an ArrayBuffer
 *
 * @param {Object} val The value to test
 * @returns {boolean} True if value is a view on an ArrayBuffer, otherwise false
 */
function isArrayBufferView(val) {
  var result;
  if ((typeof ArrayBuffer !== 'undefined') && (ArrayBuffer.isView)) {
    result = ArrayBuffer.isView(val);
  } else {
    result = (val) && (val.buffer) && (isArrayBuffer(val.buffer));
  }
  return result;
}

/**
 * Determine if a value is a String
 *
 * @param {Object} val The value to test
 * @returns {boolean} True if value is a String, otherwise false
 */
function isString(val) {
  return typeof val === 'string';
}

/**
 * Determine if a value is a Number
 *
 * @param {Object} val The value to test
 * @returns {boolean} True if value is a Number, otherwise false
 */
function isNumber(val) {
  return typeof val === 'number';
}

/**
 * Determine if a value is an Object
 *
 * @param {Object} val The value to test
 * @returns {boolean} True if value is an Object, otherwise false
 */
function isObject(val) {
  return val !== null && typeof val === 'object';
}

/**
 * Determine if a value is a plain Object
 *
 * @param {Object} val The value to test
 * @return {boolean} True if value is a plain Object, otherwise false
 */
function isPlainObject(val) {
  if (kindOf(val) !== 'object') {
    return false;
  }

  var prototype = Object.getPrototypeOf(val);
  return prototype === null || prototype === Object.prototype;
}

/**
 * Determine if a value is a Date
 *
 * @function
 * @param {Object} val The value to test
 * @returns {boolean} True if value is a Date, otherwise false
 */
var isDate = kindOfTest('Date');

/**
 * Determine if a value is a File
 *
 * @function
 * @param {Object} val The value to test
 * @returns {boolean} True if value is a File, otherwise false
 */
var isFile = kindOfTest('File');

/**
 * Determine if a value is a Blob
 *
 * @function
 * @param {Object} val The value to test
 * @returns {boolean} True if value is a Blob, otherwise false
 */
var isBlob = kindOfTest('Blob');

/**
 * Determine if a value is a FileList
 *
 * @function
 * @param {Object} val The value to test
 * @returns {boolean} True if value is a File, otherwise false
 */
var isFileList = kindOfTest('FileList');

/**
 * Determine if a value is a Function
 *
 * @param {Object} val The value to test
 * @returns {boolean} True if value is a Function, otherwise false
 */
function isFunction(val) {
  return toString.call(val) === '[object Function]';
}

/**
 * Determine if a value is a Stream
 *
 * @param {Object} val The value to test
 * @returns {boolean} True if value is a Stream, otherwise false
 */
function isStream(val) {
  return isObject(val) && isFunction(val.pipe);
}

/**
 * Determine if a value is a FormData
 *
 * @param {Object} thing The value to test
 * @returns {boolean} True if value is an FormData, otherwise false
 */
function isFormData(thing) {
  var pattern = '[object FormData]';
  return thing && (
    (typeof FormData === 'function' && thing instanceof FormData) ||
    toString.call(thing) === pattern ||
    (isFunction(thing.toString) && thing.toString() === pattern)
  );
}

/**
 * Determine if a value is a URLSearchParams object
 * @function
 * @param {Object} val The value to test
 * @returns {boolean} True if value is a URLSearchParams object, otherwise false
 */
var isURLSearchParams = kindOfTest('URLSearchParams');

/**
 * Trim excess whitespace off the beginning and end of a string
 *
 * @param {String} str The String to trim
 * @returns {String} The String freed of excess whitespace
 */
function trim(str) {
  return str.trim ? str.trim() : str.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '');
}

/**
 * Determine if we're running in a standard browser environment
 *
 * This allows axios to run in a web worker, and react-native.
 * Both environments support XMLHttpRequest, but not fully standard globals.
 *
 * web workers:
 *  typeof window -> undefined
 *  typeof document -> undefined
 *
 * react-native:
 *  navigator.product -> 'ReactNative'
 * nativescript
 *  navigator.product -> 'NativeScript' or 'NS'
 */
function isStandardBrowserEnv() {
  var product;
  if (typeof navigator !== 'undefined' && (
    (product = navigator.product) === 'ReactNative' ||
    product === 'NativeScript' ||
    product === 'NS')
  ) {
    return false;
  }

  return typeof window !== 'undefined' && typeof document !== 'undefined';
}

/**
 * Iterate over an Array or an Object invoking a function for each item.
 *
 * If `obj` is an Array callback will be called passing
 * the value, index, and complete array for each item.
 *
 * If 'obj' is an Object callback will be called passing
 * the value, key, and complete object for each property.
 *
 * @param {Object|Array} obj The object to iterate
 * @param {Function} fn The callback to invoke for each item
 */
function forEach(obj, fn) {
  // Don't bother if no value provided
  if (obj === null || typeof obj === 'undefined') {
    return;
  }

  // Force an array if not already something iterable
  if (typeof obj !== 'object') {
    /*eslint no-param-reassign:0*/
    obj = [obj];
  }

  if (isArray(obj)) {
    // Iterate over array values
    for (var i = 0, l = obj.length; i < l; i++) {
      fn.call(null, obj[i], i, obj);
    }
  } else {
    // Iterate over object keys
    for (var key in obj) {
      if (Object.prototype.hasOwnProperty.call(obj, key)) {
        fn.call(null, obj[key], key, obj);
      }
    }
  }
}

/**
 * Accepts varargs expecting each argument to be an object, then
 * immutably merges the properties of each object and returns result.
 *
 * When multiple objects contain the same key the later object in
 * the arguments list will take precedence.
 *
 * Example:
 *
 * ```js
 * var result = merge({foo: 123}, {foo: 456});
 * console.log(result.foo); // outputs 456
 * ```
 *
 * @param {Object} obj1 Object to merge
 * @returns {Object} Result of all merge properties
 */
function merge(/* obj1, obj2, obj3, ... */) {
  var result = {};
  function assignValue(val, key) {
    if (isPlainObject(result[key]) && isPlainObject(val)) {
      result[key] = merge(result[key], val);
    } else if (isPlainObject(val)) {
      result[key] = merge({}, val);
    } else if (isArray(val)) {
      result[key] = val.slice();
    } else {
      result[key] = val;
    }
  }

  for (var i = 0, l = arguments.length; i < l; i++) {
    forEach(arguments[i], assignValue);
  }
  return result;
}

/**
 * Extends object a by mutably adding to it the properties of object b.
 *
 * @param {Object} a The object to be extended
 * @param {Object} b The object to copy properties from
 * @param {Object} thisArg The object to bind function to
 * @return {Object} The resulting value of object a
 */
function extend(a, b, thisArg) {
  forEach(b, function assignValue(val, key) {
    if (thisArg && typeof val === 'function') {
      a[key] = bind(val, thisArg);
    } else {
      a[key] = val;
    }
  });
  return a;
}

/**
 * Remove byte order marker. This catches EF BB BF (the UTF-8 BOM)
 *
 * @param {string} content with BOM
 * @return {string} content value without BOM
 */
function stripBOM(content) {
  if (content.charCodeAt(0) === 0xFEFF) {
    content = content.slice(1);
  }
  return content;
}

/**
 * Inherit the prototype methods from one constructor into another
 * @param {function} constructor
 * @param {function} superConstructor
 * @param {object} [props]
 * @param {object} [descriptors]
 */

function inherits(constructor, superConstructor, props, descriptors) {
  constructor.prototype = Object.create(superConstructor.prototype, descriptors);
  constructor.prototype.constructor = constructor;
  props && Object.assign(constructor.prototype, props);
}

/**
 * Resolve object with deep prototype chain to a flat object
 * @param {Object} sourceObj source object
 * @param {Object} [destObj]
 * @param {Function|Boolean} [filter]
 * @param {Function} [propFilter]
 * @returns {Object}
 */

function toFlatObject(sourceObj, destObj, filter, propFilter) {
  var props;
  var i;
  var prop;
  var merged = {};

  destObj = destObj || {};
  // eslint-disable-next-line no-eq-null,eqeqeq
  if (sourceObj == null) return destObj;

  do {
    props = Object.getOwnPropertyNames(sourceObj);
    i = props.length;
    while (i-- > 0) {
      prop = props[i];
      if ((!propFilter || propFilter(prop, sourceObj, destObj)) && !merged[prop]) {
        destObj[prop] = sourceObj[prop];
        merged[prop] = true;
      }
    }
    sourceObj = filter !== false && Object.getPrototypeOf(sourceObj);
  } while (sourceObj && (!filter || filter(sourceObj, destObj)) && sourceObj !== Object.prototype);

  return destObj;
}

/*
 * determines whether a string ends with the characters of a specified string
 * @param {String} str
 * @param {String} searchString
 * @param {Number} [position= 0]
 * @returns {boolean}
 */
function endsWith(str, searchString, position) {
  str = String(str);
  if (position === undefined || position > str.length) {
    position = str.length;
  }
  position -= searchString.length;
  var lastIndex = str.indexOf(searchString, position);
  return lastIndex !== -1 && lastIndex === position;
}

/**
 * Returns new array from array like object or null if failed
 * @param {*} [thing]
 * @returns {?Array}
 */
function toArray(thing) {
  if (!thing) return null;
  if (isArray(thing)) return thing;
  var i = thing.length;
  if (!isNumber(i)) return null;
  var arr = new Array(i);
  while (i-- > 0) {
    arr[i] = thing[i];
  }
  return arr;
}

// eslint-disable-next-line func-names
var isTypedArray = (function(TypedArray) {
  // eslint-disable-next-line func-names
  return function(thing) {
    return TypedArray && thing instanceof TypedArray;
  };
})(typeof Uint8Array !== 'undefined' && Object.getPrototypeOf(Uint8Array));

function forEachEntry(obj, fn) {
  var generator = obj && obj[Symbol.iterator];

  var iterator = generator.call(obj);

  var result;

  while ((result = iterator.next()) && !result.done) {
    var pair = result.value;
    fn.call(obj, pair[0], pair[1]);
  }
}

function matchAll(regExp, str) {
  var matches;
  var arr = [];

  while ((matches = regExp.exec(str)) !== null) {
    arr.push(matches);
  }

  return arr;
}

var isHTMLForm = kindOfTest('HTMLFormElement');

var hasOwnProperty = (function resolver(_hasOwnProperty) {
  return function(obj, prop) {
    return _hasOwnProperty.call(obj, prop);
  };
})(Object.prototype.hasOwnProperty);

module.exports = {
  isArray: isArray,
  isArrayBuffer: isArrayBuffer,
  isBuffer: isBuffer,
  isFormData: isFormData,
  isArrayBufferView: isArrayBufferView,
  isString: isString,
  isNumber: isNumber,
  isObject: isObject,
  isPlainObject: isPlainObject,
  isUndefined: isUndefined,
  isDate: isDate,
  isFile: isFile,
  isBlob: isBlob,
  isFunction: isFunction,
  isStream: isStream,
  isURLSearchParams: isURLSearchParams,
  isStandardBrowserEnv: isStandardBrowserEnv,
  forEach: forEach,
  merge: merge,
  extend: extend,
  trim: trim,
  stripBOM: stripBOM,
  inherits: inherits,
  toFlatObject: toFlatObject,
  kindOf: kindOf,
  kindOfTest: kindOfTest,
  endsWith: endsWith,
  toArray: toArray,
  isTypedArray: isTypedArray,
  isFileList: isFileList,
  forEachEntry: forEachEntry,
  matchAll: matchAll,
  isHTMLForm: isHTMLForm,
  hasOwnProperty: hasOwnProperty
};
<commit_msg>chore(Utils): added docs for utils functions<commit_after>'use strict';

var bind = require('./helpers/bind');

// utils is a library of generic helper functions non-specific to axios

var toString = Object.prototype.toString;

// eslint-disable-next-line func-names
var kindOf = (function(cache) {
  // eslint-disable-next-line func-names
  return function(thing) {
    var str = toString.call(thing);
    return cache[str] || (cache[str] = str.slice(8, -1).toLowerCase());
  };
})(Object.create(null));

function kindOfTest(type) {
  type = type.toLowerCase();
  return function isKindOf(thing) {
    return kindOf(thing) === type;
  };
}

/**
 * Determine if a value is an Array
 *
 * @param {Object} val The value to test
 *
 * @returns {boolean} True if value is an Array, otherwise false
 */
function isArray(val) {
  return Array.isArray(val);
}

/**
 * Determine if a value is undefined
 *
 * @param {Object} val The value to test
 *
 * @returns {boolean} True if the value is undefined, otherwise false
 */
function isUndefined(val) {
  return typeof val === 'undefined';
}

/**
 * Determine if a value is a Buffer
 *
 * @param {Object} val The value to test
 *
 * @returns {boolean} True if value is a Buffer, otherwise false
 */
function isBuffer(val) {
  return val !== null && !isUndefined(val) && val.constructor !== null && !isUndefined(val.constructor)
    && typeof val.constructor.isBuffer === 'function' && val.constructor.isBuffer(val);
}

/**
 * Determine if a value is an ArrayBuffer
 *
 * @param {Object} val The value to test
 *
 * @returns {boolean} True if value is an ArrayBuffer, otherwise false
 */
var isArrayBuffer = kindOfTest('ArrayBuffer');

/**
 * Determine if a value is a view on an ArrayBuffer
 *
 * @param {Object} val The value to test
 *
 * @returns {boolean} True if value is a view on an ArrayBuffer, otherwise false
 */
function isArrayBufferView(val) {
  var result;
  if ((typeof ArrayBuffer !== 'undefined') && (ArrayBuffer.isView)) {
    result = ArrayBuffer.isView(val);
  } else {
    result = (val) && (val.buffer) && (isArrayBuffer(val.buffer));
  }
  return result;
}

/**
 * Determine if a value is a String
 *
 * @param {Object} val The value to test
 *
 * @returns {boolean} True if value is a String, otherwise false
 */
function isString(val) {
  return typeof val === 'string';
}

/**
 * Determine if a value is a Number
 *
 * @param {Object} val The value to test
 *
 * @returns {boolean} True if value is a Number, otherwise false
 */
function isNumber(val) {
  return typeof val === 'number';
}

/**
 * Determine if a value is an Object
 *
 * @param {Object} val The value to test
 *
 * @returns {boolean} True if value is an Object, otherwise false
 */
function isObject(val) {
  return val !== null && typeof val === 'object';
}

/**
 * Determine if a value is a plain Object
 *
 * @param {Object} val The value to test
 *
 * @returns {boolean} True if value is a plain Object, otherwise false
 */
function isPlainObject(val) {
  if (kindOf(val) !== 'object') {
    return false;
  }

  var prototype = Object.getPrototypeOf(val);
  return prototype === null || prototype === Object.prototype;
}

/**
 * Determine if a value is a Date
 *
 * @param {Object} val The value to test
 *
 * @returns {boolean} True if value is a Date, otherwise false
 */
var isDate = kindOfTest('Date');

/**
 * Determine if a value is a File
 *
 * @param {Object} val The value to test
 *
 * @returns {boolean} True if value is a File, otherwise false
 */
var isFile = kindOfTest('File');

/**
 * Determine if a value is a Blob
 *
 * @param {Object} val The value to test
 *
 * @returns {boolean} True if value is a Blob, otherwise false
 */
var isBlob = kindOfTest('Blob');

/**
 * Determine if a value is a FileList
 *
 * @param {Object} val The value to test
 *
 * @returns {boolean} True if value is a File, otherwise false
 */
var isFileList = kindOfTest('FileList');

/**
 * Determine if a value is a Function
 *
 * @param {Object} val The value to test
 *
 * @returns {boolean} True if value is a Function, otherwise false
 */
function isFunction(val) {
  return toString.call(val) === '[object Function]';
}

/**
 * Determine if a value is a Stream
 *
 * @param {Object} val The value to test
 *
 * @returns {boolean} True if value is a Stream, otherwise false
 */
function isStream(val) {
  return isObject(val) && isFunction(val.pipe);
}

/**
 * Determine if a value is a FormData
 *
 * @param {Object} thing The value to test
 *
 * @returns {boolean} True if value is an FormData, otherwise false
 */
function isFormData(thing) {
  var pattern = '[object FormData]';
  return thing && (
    (typeof FormData === 'function' && thing instanceof FormData) ||
    toString.call(thing) === pattern ||
    (isFunction(thing.toString) && thing.toString() === pattern)
  );
}

/**
 * Determine if a value is a URLSearchParams object
 *
 * @param {Object} val The value to test
 *
 * @returns {boolean} True if value is a URLSearchParams object, otherwise false
 */
var isURLSearchParams = kindOfTest('URLSearchParams');

/**
 * Trim excess whitespace off the beginning and end of a string
 *
 * @param {String} str The String to trim
 *
 * @returns {String} The String freed of excess whitespace
 */
function trim(str) {
  return str.trim ? str.trim() : str.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '');
}

/**
 * Determine if we're running in a standard browser environment
 *
 * This allows axios to run in a web worker, and react-native.
 * Both environments support XMLHttpRequest, but not fully standard globals.
 *
 * web workers:
 *  typeof window -> undefined
 *  typeof document -> undefined
 *
 * react-native:
 *  navigator.product -> 'ReactNative'
 * nativescript
 *  navigator.product -> 'NativeScript' or 'NS'
 *
 * @returns {boolean}
 */
function isStandardBrowserEnv() {
  var product;
  if (typeof navigator !== 'undefined' && (
    (product = navigator.product) === 'ReactNative' ||
    product === 'NativeScript' ||
    product === 'NS')
  ) {
    return false;
  }

  return typeof window !== 'undefined' && typeof document !== 'undefined';
}

/**
 * Iterate over an Array or an Object invoking a function for each item.
 *
 * If `obj` is an Array callback will be called passing
 * the value, index, and complete array for each item.
 *
 * If 'obj' is an Object callback will be called passing
 * the value, key, and complete object for each property.
 *
 * @param {Object|Array} obj The object to iterate
 * @param {Function} fn The callback to invoke for each item
 *
 * @returns {void}
 */
function forEach(obj, fn) {
  // Don't bother if no value provided
  if (obj === null || typeof obj === 'undefined') {
    return;
  }

  // Force an array if not already something iterable
  if (typeof obj !== 'object') {
    /*eslint no-param-reassign:0*/
    obj = [obj];
  }

  if (isArray(obj)) {
    // Iterate over array values
    for (var i = 0, l = obj.length; i < l; i++) {
      fn.call(null, obj[i], i, obj);
    }
  } else {
    // Iterate over object keys
    for (var key in obj) {
      if (Object.prototype.hasOwnProperty.call(obj, key)) {
        fn.call(null, obj[key], key, obj);
      }
    }
  }
}

/**
 * Accepts varargs expecting each argument to be an object, then
 * immutably merges the properties of each object and returns result.
 *
 * When multiple objects contain the same key the later object in
 * the arguments list will take precedence.
 *
 * Example:
 *
 * ```js
 * var result = merge({foo: 123}, {foo: 456});
 * console.log(result.foo); // outputs 456
 * ```
 *
 * @param {Object} obj1 Object to merge
 *
 * @returns {Object} Result of all merge properties
 */
function merge(/* obj1, obj2, obj3, ... */) {
  var result = {};
  function assignValue(val, key) {
    if (isPlainObject(result[key]) && isPlainObject(val)) {
      result[key] = merge(result[key], val);
    } else if (isPlainObject(val)) {
      result[key] = merge({}, val);
    } else if (isArray(val)) {
      result[key] = val.slice();
    } else {
      result[key] = val;
    }
  }

  for (var i = 0, l = arguments.length; i < l; i++) {
    forEach(arguments[i], assignValue);
  }
  return result;
}

/**
 * Extends object a by mutably adding to it the properties of object b.
 *
 * @param {Object} a The object to be extended
 * @param {Object} b The object to copy properties from
 * @param {Object} thisArg The object to bind function to
 *
 * @returns {Object} The resulting value of object a
 */
function extend(a, b, thisArg) {
  forEach(b, function assignValue(val, key) {
    if (thisArg && typeof val === 'function') {
      a[key] = bind(val, thisArg);
    } else {
      a[key] = val;
    }
  });
  return a;
}

/**
 * Remove byte order marker. This catches EF BB BF (the UTF-8 BOM)
 *
 * @param {string} content with BOM
 *
 * @returns {string} content value without BOM
 */
function stripBOM(content) {
  if (content.charCodeAt(0) === 0xFEFF) {
    content = content.slice(1);
  }
  return content;
}

/**
 * Inherit the prototype methods from one constructor into another
 * @param {function} constructor
 * @param {function} superConstructor
 * @param {object} [props]
 * @param {object} [descriptors]
 *
 * @returns {void}
 */
function inherits(constructor, superConstructor, props, descriptors) {
  constructor.prototype = Object.create(superConstructor.prototype, descriptors);
  constructor.prototype.constructor = constructor;
  props && Object.assign(constructor.prototype, props);
}

/**
 * Resolve object with deep prototype chain to a flat object
 * @param {Object} sourceObj source object
 * @param {Object} [destObj]
 * @param {Function|Boolean} [filter]
 * @param {Function} [propFilter]
 *
 * @returns {Object}
 */
function toFlatObject(sourceObj, destObj, filter, propFilter) {
  var props;
  var i;
  var prop;
  var merged = {};

  destObj = destObj || {};
  // eslint-disable-next-line no-eq-null,eqeqeq
  if (sourceObj == null) return destObj;

  do {
    props = Object.getOwnPropertyNames(sourceObj);
    i = props.length;
    while (i-- > 0) {
      prop = props[i];
      if ((!propFilter || propFilter(prop, sourceObj, destObj)) && !merged[prop]) {
        destObj[prop] = sourceObj[prop];
        merged[prop] = true;
      }
    }
    sourceObj = filter !== false && Object.getPrototypeOf(sourceObj);
  } while (sourceObj && (!filter || filter(sourceObj, destObj)) && sourceObj !== Object.prototype);

  return destObj;
}

/**
 * Determines whether a string ends with the characters of a specified string
 *
 * @param {String} str
 * @param {String} searchString
 * @param {Number} [position= 0]
 *
 * @returns {boolean}
 */
function endsWith(str, searchString, position) {
  str = String(str);
  if (position === undefined || position > str.length) {
    position = str.length;
  }
  position -= searchString.length;
  var lastIndex = str.indexOf(searchString, position);
  return lastIndex !== -1 && lastIndex === position;
}

/**
 * Returns new array from array like object or null if failed
 *
 * @param {*} [thing]
 *
 * @returns {?Array}
 */
function toArray(thing) {
  if (!thing) return null;
  if (isArray(thing)) return thing;
  var i = thing.length;
  if (!isNumber(i)) return null;
  var arr = new Array(i);
  while (i-- > 0) {
    arr[i] = thing[i];
  }
  return arr;
}

/**
 * Checking if the Uint8Array exists and if it does, it returns a function that checks if the
 * thing passed in is an instance of Uint8Array
 *
 * @param {TypedArray}
 *
 * @returns {Array}
 */
// eslint-disable-next-line func-names
var isTypedArray = (function(TypedArray) {
  // eslint-disable-next-line func-names
  return function(thing) {
    return TypedArray && thing instanceof TypedArray;
  };
})(typeof Uint8Array !== 'undefined' && Object.getPrototypeOf(Uint8Array));

/**
 * For each entry in the object, call the function with the key and value.
 *
 * @param {Object<any, any>} obj - The object to iterate over.
 * @param {Function} fn - The function to call for each entry.
 *
 * @returns {void}
 */
function forEachEntry(obj, fn) {
  var generator = obj && obj[Symbol.iterator];

  var iterator = generator.call(obj);

  var result;

  while ((result = iterator.next()) && !result.done) {
    var pair = result.value;
    fn.call(obj, pair[0], pair[1]);
  }
}

/**
 * It takes a regular expression and a string, and returns an array of all the matches
 *
 * @param {string} regExp - The regular expression to match against.
 * @param {string} str - The string to search.
 *
 * @returns {Array<boolean>}
 */
function matchAll(regExp, str) {
  var matches;
  var arr = [];

  while ((matches = regExp.exec(str)) !== null) {
    arr.push(matches);
  }

  return arr;
}

/* Checking if the kindOfTest function returns true when passed an HTMLFormElement. */
var isHTMLForm = kindOfTest('HTMLFormElement');

/* Creating a function that will check if an object has a property. */
var hasOwnProperty = (function resolver(_hasOwnProperty) {
  return function(obj, prop) {
    return _hasOwnProperty.call(obj, prop);
  };
})(Object.prototype.hasOwnProperty);

module.exports = {
  isArray: isArray,
  isArrayBuffer: isArrayBuffer,
  isBuffer: isBuffer,
  isFormData: isFormData,
  isArrayBufferView: isArrayBufferView,
  isString: isString,
  isNumber: isNumber,
  isObject: isObject,
  isPlainObject: isPlainObject,
  isUndefined: isUndefined,
  isDate: isDate,
  isFile: isFile,
  isBlob: isBlob,
  isFunction: isFunction,
  isStream: isStream,
  isURLSearchParams: isURLSearchParams,
  isStandardBrowserEnv: isStandardBrowserEnv,
  forEach: forEach,
  merge: merge,
  extend: extend,
  trim: trim,
  stripBOM: stripBOM,
  inherits: inherits,
  toFlatObject: toFlatObject,
  kindOf: kindOf,
  kindOfTest: kindOfTest,
  endsWith: endsWith,
  toArray: toArray,
  isTypedArray: isTypedArray,
  isFileList: isFileList,
  forEachEntry: forEachEntry,
  matchAll: matchAll,
  isHTMLForm: isHTMLForm,
  hasOwnProperty: hasOwnProperty
};
<|endoftext|>


<commit_before>
/*

  Utils.js

*/

var __rootDir = process.cwd(),
    fs        = require("fs"),
    url       = require("url"),
    path      = require("path"),
    Utils;

module.exports = Utils = {};

/*

  function getRootPath

*/

Utils.getRootPath = function() {
  return __rootDir;
}

/*

  function makePathAbsolute

*/

Utils.makePathAbsolute = function(p) {

  return path.resolve(Utils.getRootPath(), p || "");

}

/*

  function eachFile

*/

Utils.eachFile = function(p, fn, recursive) {

  // Make path absolute before call (for comparison after)
  p = Utils.makePathAbsolute(p);

  Utils.readDirectory(p, recursive).forEach(function(file) {
    file.folder = path.relative(p, file.path.replace(new RegExp(file.base + "$"), ""));
    fn(file);
  });

}

/*

  function makeUrls

*/

Utils.makeUrls = function(route, file, type) {

  var base, slugs;

  type  = ("undefined" == typeof type) ? "" : ("." + type).replace(/\.+/, ".");
  base  = url.resolve((route + "/").replace(/\/\/$/, "/"), file.folder),
  slugs = [url.resolve(base, file.name + type)];

  // HTML files are special cases: we allow the original extension, the "html"
  // extension, and if the file is named "index", we allow it to function as the folder
  if (/\.?html$/.test(type)) {
    slugs.push(url.resolve(base, file.name));
    if ("index" === file.name) slugs.push(base)
  }

  return slugs;

}

/*

  function readDirectory

*/

Utils.readDirectory = function(p, recursive) {

  var results = [];

  // Set defaults
  if ("undefined" == typeof recursive) recursive = true;
  p = Utils.makePathAbsolute(p);

  // Read in files
  fs.readdirSync(p).forEach(function(file) {

    var stats, parsed;

    // Read file and stats
    file = path.join(p, file);
    stats = fs.lstatSync(file);

    // Recursively walk directory, or add file
    if (stats.isDirectory()) {
      if (recursive)
        results = results.concat(Utils.readDirectory(file, true))
    } else {
      parsed = path.parse(file);
      parsed.path = file;
      results.push(parsed);
    }

  });

  return results;

}
<commit_msg>Utils/eachFile: allows filtering capabilities<commit_after>
/*

  Utils.js

*/

var __rootDir = process.cwd(),
    fs        = require("fs"),
    url       = require("url"),
    path      = require("path"),
    Utils;

module.exports = Utils = {};

/*

  function getRootPath

*/

Utils.getRootPath = function() {
  return __rootDir;
}

/*

  function makePathAbsolute

*/

Utils.makePathAbsolute = function(p) {

  return path.resolve(Utils.getRootPath(), p || "");

}

/*

  function eachFile

*/

Utils.eachFile = function(p, options, fn) {

  // Allow polymorphism
  if ("function" == typeof options) {
    fn = options;
    options = {};
  }

  // Make path absolute before call (for comparison after)
  p = Utils.makePathAbsolute(p);

  Utils.readDirectory(p, options.recursive).forEach(function(file) {
    file.folder = path.relative(p, file.path.replace(new RegExp(file.base + "$"), ""));
    if (!options.filter || options.filter.indexOf(file.ext) > -1) fn(file);
  });

}

/*

  function makeUrls

*/

Utils.makeUrls = function(route, file, type) {

  var base, slugs;

  type  = ("undefined" == typeof type) ? "" : ("." + type).replace(/\.+/, ".");
  base  = url.resolve((route + "/").replace(/\/\/$/, "/"), file.folder),
  slugs = [url.resolve(base, file.name + type)];

  // HTML files are special cases: we allow the original extension, the "html"
  // extension, and if the file is named "index", we allow it to function as the folder
  if (/\.?html$/.test(type)) {
    slugs.push(url.resolve(base, file.name));
    if ("index" === file.name) slugs.push(base)
  }

  return slugs;

}

/*

  function readDirectory

*/

Utils.readDirectory = function(p, recursive) {

  var results = [];

  // Set defaults
  if ("undefined" == typeof recursive) recursive = true;
  p = Utils.makePathAbsolute(p);

  // Read in files
  fs.readdirSync(p).forEach(function(file) {

    var stats, parsed;

    // Read file and stats
    file = path.join(p, file);
    stats = fs.lstatSync(file);

    // Recursively walk directory, or add file
    if (stats.isDirectory()) {
      if (recursive)
        results = results.concat(Utils.readDirectory(file, true))
    } else {
      parsed = path.parse(file);
      parsed.path = file;
      results.push(parsed);
    }

  });

  return results;

}
<|endoftext|>


<commit_before>"use strict";

exports.getNamesFromPattern = function (pattern) {
  var queue = [pattern];
  var names = [];

  for (var i = 0; i < queue.length; ++i) {
    var pattern = queue[i];
    if (! pattern) {
      continue;
    }

    switch (pattern.type) {
    case "Identifier":
      names.push(pattern.name);
      break;
    case "Property":
    case "ObjectProperty":
      queue.push(pattern.value);
      break;
    case "AssignmentPattern":
      queue.push(pattern.left);
      break;
    case "ObjectPattern":
      queue.push.apply(queue, pattern.properties);
      break;
    case "ArrayPattern":
      queue.push.apply(queue, pattern.elements);
      break;
    case "RestElement":
      queue.push(pattern.argument);
      break;
    }
  }

  return names;
};
<commit_msg>Remove dead code from `getNamesFromPattern`.<commit_after>"use strict";

exports.getNamesFromPattern = function (pattern) {
  var queue = [pattern];
  var names = [];

  for (var i = 0; i < queue.length; ++i) {
    var pattern = queue[i];

    switch (pattern.type) {
    case "Identifier":
      names.push(pattern.name);
      break;
    case "Property":
    case "ObjectProperty":
      queue.push(pattern.value);
      break;
    case "AssignmentPattern":
      queue.push(pattern.left);
      break;
    case "ObjectPattern":
      queue.push.apply(queue, pattern.properties);
      break;
    case "ArrayPattern":
      queue.push.apply(queue, pattern.elements);
      break;
    case "RestElement":
      queue.push(pattern.argument);
      break;
    }
  }

  return names;
};
<|endoftext|>