<commit_before>// Browser and Node shared fixtures for the `gpii.pouch` PouchDB component tests.
/* eslint-env node */
"use strict";
var fluid  = fluid || require("infusion");
var gpii   = fluid.registerNamespace("gpii");
var jqUnit = jqUnit || require("node-jqunit");

if (!gpii.pouch) {
    require("../../../")
    gpii.pouch.loadTestingSupport();
}

fluid.registerNamespace("gpii.tests.pouchdb.component.common");

// A simple function to test support for "map" functions using the query method.
/* globals emit */
gpii.tests.pouchdb.component.common.map = function (doc) {
    if (doc.color) {
        emit(doc.color, doc);
    }
};

// A simple function to test the support for "reduce" functions using the query method.
gpii.tests.pouchdb.component.common.reduce = function (keys, values, rereduce) {
    var colorSummary = {};
    if (rereduce) {
        values.forEach(function (toReduce) {
            Object.keys(toReduce).forEach(function (key) {
                var subtotal = toReduce[key];
                colorSummary[key] = colorSummary[key] ? colorSummary[key] + subtotal : subtotal;
            });
        });
    }
    else {
        keys.forEach(function (entry) {
            var color = entry[0];
            colorSummary[color] = colorSummary[color] ? colorSummary[color] + 1 : 1;
        });
    }
    return colorSummary; // { red: 1, yellow: 2 }
};

fluid.defaults("gpii.tests.pouchdb.component.common.caseHolder.base", {
    gradeNames: ["gpii.test.express.caseHolder.base"],
    // Recreate the database before each test.
    sequenceStart: [{
        func: "{testEnvironment}.events.constructFixtures.fire"
    }],
    // Destroy the database after each test.
    sequenceEnd:   [
        {
            func: "{testEnvironment}.pouchDb.destroyPouch"
        },
        {
            event:    "{testEnvironment}.pouchDb.events.onDestroyPouchComplete",
            listener: "jqUnit.assertLeftHand",
            args:     ["The database should be destroyed on test completion...", { ok: true}, "{arguments}.0"]
        }
    ]
});

fluid.defaults("gpii.tests.pouchdb.component.common.caseHolder", {
    gradeNames: ["gpii.tests.pouchdb.component.common.caseHolder.base"],
    inputs: {
        bulkData: [
            {
                "_id": "one",
                "saying": "is the loneliest number"
            },
            {
                "_id": "two",
                "saying": "are required to tango"
            }
        ],
        mapReduce: [
            {
                "color": "red",
                "name": "strawberry"
            },
            {
                "color": "yellow",
                "name": "banana"
            },
            {
                "color": "red",
                "name": "cherry"
            },
            {
                "color": "blue",
                "name": "blueberry"
            },
            {
                name: "colorless glass noodles"
            }
        ]
    },
    expectedResponses: {
        bulkCreate: [{ ok: true, id: "one"}, { ok: true, id: "two"}]
    },
    rawModules: [{
        name: "Common tests for `gpii.pouch` component...",
        type: "test",
        tests: [
            {
                name: "Test the `info` method...",
                sequence: [
                    {
                        func: "{testEnvironment}.pouchDb.info"
                    },
                    {
                        event:    "{testEnvironment}.pouchDb.events.onInfoComplete",
                        listener: "jqUnit.assertLeftHand",
                        args:     ["The database info should be as expected...", { db_name: "test", doc_count: 0, update_seq: 0}, "{arguments}.0"]
                    }
                ]
            },
            {
                name: "Test the `POST` method (with an ID)...",
                sequence: [
                    {
                        func: "{testEnvironment}.pouchDb.post",
                        args: [{ _id: "foo"}]
                    },
                    {
                        event: "{testEnvironment}.pouchDb.events.onPostComplete",
                        listener: "jqUnit.assertLeftHand",
                        args: ["The POST should have been successful...", { ok: true, id: "foo"}, "{arguments}.0"]
                    }
                ]
            },
            {
                name: "Test the `GET` method (with a non-existent ID)...",
                sequence: [
                    {
                        func: "{testEnvironment}.pouchDb.get",
                        args: [{ _id: "notGonnaFindIt"}]
                    },
                    {
                        event: "{testEnvironment}.pouchDb.events.onError",
                        listener: "jqUnit.assert",
                        args: ["An error should be thrown if a record cannot be found..."]
                    }
                ]
            },
            {
                name: "Test the `PUT` method (with an ID)...",
                sequence: [
                    {
                        func: "{testEnvironment}.pouchDb.post",
                        args: [{ _id: "bar"}]
                    },
                    {
                        event: "{testEnvironment}.pouchDb.events.onPostComplete",
                        listener: "jqUnit.assertLeftHand",
                        args: ["The PUT should have been successful...", { ok: true, id: "bar"}, "{arguments}.0"]
                    }
                ]
            },
            {
                name: "Test the `POST` method (without an ID)...",
                sequence: [
                    {
                        func: "{testEnvironment}.pouchDb.post",
                        args: [{ "onions": "raw" }]
                    },
                    {
                        event: "{testEnvironment}.pouchDb.events.onPostComplete",
                        listener: "{testEnvironment}.pouchDb.get",
                        args: ["{arguments}.0.id"]
                    },
                    {
                        event: "{testEnvironment}.pouchDb.events.onGetComplete",
                        listener: "jqUnit.assertLeftHand",
                        args: ["The record should have been POSTed...", { "onions": "raw"}, "{arguments}.0"]
                    }
                ]
            },
            {
                name: "Test the `bulkDocs` function...",
                sequence: [
                    {
                        func: "{testEnvironment}.pouchDb.bulkDocs",
                        args: ["{that}.options.inputs.bulkData"]
                    },
                    {
                        event:    "{testEnvironment}.pouchDb.events.onBulkDocsComplete",
                        listener: "gpii.test.pouchdb.recordsAreEquivalent",
                        args:     ["The bulk creation of documents should have been successful...", "{that}.options.expectedResponses.bulkCreate", "{arguments}.0"]
                    }
                ]
            },
            {
                name: "Test the `allDocs` function...",
                sequence: [
                    {
                        func: "{testEnvironment}.pouchDb.bulkDocs",
                        args: ["{that}.options.inputs.bulkData"]
                    },
                    {
                        event:    "{testEnvironment}.pouchDb.events.onBulkDocsComplete",
                        listener: "{testEnvironment}.pouchDb.allDocs",
                        args:     []
                    },
                    {
                        event:    "{testEnvironment}.pouchDb.events.onAllDocsComplete",
                        listener: "jqUnit.assertLeftHand",
                        args:     ["The bulk retrieval of all documents should return the correct number of records...", { offset: 0, total_rows: 2 }, "{arguments}.0"]
                    }
                ]
            },
            {
                name: "Test the `bulkGet` function...",
                sequence: [
                    {
                        func: "{testEnvironment}.pouchDb.bulkDocs",
                        args: ["{that}.options.inputs.bulkData"]
                    },
                    {
                        event:    "{testEnvironment}.pouchDb.events.onBulkDocsComplete",
                        listener: "{testEnvironment}.pouchDb.bulkGet",
                        args:     [{ docs: [{ id: "one" }, { id: "two"}]}]
                    },
                    {
                        event:    "{testEnvironment}.pouchDb.events.onBulkGetComplete",
                        listener: "gpii.test.pouchdb.recordsAreEquivalent",
                        args:     ["a bulk get of all documents should return the correct content...", [{ id: "one" }, { id: "two"}], "{arguments}.0.results"]
                    }
                ]
            },
            {
                name: "Test the `remove` function...",
                sequence: [
                    {
                        func: "{testEnvironment}.pouchDb.bulkDocs",
                        args: ["{that}.options.inputs.bulkData"]
                    },
                    {
                        event:    "{testEnvironment}.pouchDb.events.onBulkDocsComplete",
                        listener: "{testEnvironment}.pouchDb.get",
                        args:     ["two"]
                    },
                    {
                        event:    "{testEnvironment}.pouchDb.events.onGetComplete",
                        listener: "{testEnvironment}.pouchDb.remove",
                        args:     ["{arguments}.0"]
                    },
                    {
                        event:    "{testEnvironment}.pouchDb.events.onRemoveComplete",
                        listener: "{testEnvironment}.pouchDb.info",
                        args:     []
                    },
                    {
                        event:    "{testEnvironment}.pouchDb.events.onInfoComplete",
                        listener: "jqUnit.assertLeftHand",
                        args:     ["The database should now only contain one record...", { db_name: "test", doc_count: 1 }, "{arguments}.0"]
                    }
                ]
            },
            {
                name: "Test the `remove` method (with a non-existent ID)...",
                sequence: [
                    {
                        func: "{testEnvironment}.pouchDb.remove",
                        args: [{ _id: "notGonnaFindIt"}]
                    },
                    {
                        event: "{testEnvironment}.pouchDb.events.onError",
                        listener: "jqUnit.assert",
                        args: ["An error should be thrown if a record cannot be found..."]
                    }
                ]
            },
            {
                name: "Testing `query` handling (passing a single map function)...",
                sequence: [
                    {
                        func: "{testEnvironment}.pouchDb.bulkDocs",
                        args: ["{that}.options.inputs.mapReduce"]
                    },
                    {
                        event:    "{testEnvironment}.pouchDb.events.onBulkDocsComplete",
                        listener: "{testEnvironment}.pouchDb.query",
                        args:     [gpii.tests.pouchdb.component.common.map]
                    },
                    {
                        event:    "{testEnvironment}.pouchDb.events.onQueryComplete",
                        listener: "jqUnit.assertEquals",
                        args:     ["The view should return the right number of records...", 4, "{arguments}.0.rows.length" ]
                    }
                ]
            },
            {
                name: "Testing `query` handling (passing a map function as part of a JSON document)...",
                sequence: [
                    {
                        func: "{testEnvironment}.pouchDb.bulkDocs",
                        args: ["{that}.options.inputs.mapReduce"]
                    },
                    {
                        event:    "{testEnvironment}.pouchDb.events.onBulkDocsComplete",
                        listener: "{testEnvironment}.pouchDb.query",
                        args:     [{ map: gpii.tests.pouchdb.component.common.map}]
                    },
                    {
                        event:    "{testEnvironment}.pouchDb.events.onQueryComplete",
                        listener: "jqUnit.assertEquals",
                        args:     ["The view should return the right number of records...", 4, "{arguments}.0.rows.length" ]
                    }
                ]
            },
            {
                name: "Testing `query` handling (passing both map and reduce function)...",
                sequence: [
                    {
                        func: "{testEnvironment}.pouchDb.bulkDocs",
                        args: ["{that}.options.inputs.mapReduce"]
                    },
                    {
                        event:    "{testEnvironment}.pouchDb.events.onBulkDocsComplete",
                        listener: "{testEnvironment}.pouchDb.query",
                        args:     [{ map: gpii.tests.pouchdb.component.common.map, reduce: gpii.tests.pouchdb.component.common.reduce}]
                    },
                    {
                        event:    "{testEnvironment}.pouchDb.events.onQueryComplete",
                        listener: "jqUnit.assertDeepEq",
                        args:     ["The reduced data should be correct...", { red: 2, yellow: 1, blue: 1 }, "{arguments}.0.rows.0.value" ]
                    }
                ]
            }
        ]
    }]
});

fluid.defaults("gpii.tests.pouchdb.component.common.environment", {
    gradeNames: ["fluid.test.testEnvironment"],
    events: {
        constructFixtures: null
    },
    components: {
        pouchDb: {
            type: "gpii.pouch",
            createOnEvent: "constructFixtures",
            options: {
                dbOptions: {
                    name: "test"
                }
            }
        },
        caseHolder: {
            type: "gpii.tests.pouchdb.component.common.caseHolder"
        }
    }
});
<commit_msg>GPII-1897:  Improved documentation for test map/reduce functions.<commit_after>// Browser and Node shared fixtures for the `gpii.pouch` PouchDB component tests.
/* eslint-env node */
"use strict";
var fluid  = fluid || require("infusion");
var gpii   = fluid.registerNamespace("gpii");
var jqUnit = jqUnit || require("node-jqunit");

if (!gpii.pouch) {
    require("../../../")
    gpii.pouch.loadTestingSupport();
}

fluid.registerNamespace("gpii.tests.pouchdb.component.common");

// A CouchDB "map" function to test the `query` method.  The view only returns records that have a `color` value.
// See http://wiki.apache.org/couchdb/Introduction_to_CouchDB_views#Map_Functions
/* globals emit */
gpii.tests.pouchdb.component.common.map = function (doc) {
    if (doc.color) {
        emit(doc.color, doc);
    }
};

// A CouchDB "reduce" function to test the query method.  Generates a count of records by `color` value.
// See: http://wiki.apache.org/couchdb/Introduction_to_CouchDB_views#Reduce_Functions
gpii.tests.pouchdb.component.common.reduce = function (keys, values, rereduce) {
    var colorSummary = {};
    if (rereduce) {
        values.forEach(function (toReduce) {
            Object.keys(toReduce).forEach(function (key) {
                var subtotal = toReduce[key];
                colorSummary[key] = colorSummary[key] ? colorSummary[key] + subtotal : subtotal;
            });
        });
    }
    else {
        keys.forEach(function (entry) {
            var color = entry[0];
            colorSummary[color] = colorSummary[color] ? colorSummary[color] + 1 : 1;
        });
    }
    return colorSummary; // { red: 1, yellow: 2 }
};

fluid.defaults("gpii.tests.pouchdb.component.common.caseHolder.base", {
    gradeNames: ["gpii.test.express.caseHolder.base"],
    // Recreate the database before each test.
    sequenceStart: [{
        func: "{testEnvironment}.events.constructFixtures.fire"
    }],
    // Destroy the database after each test.
    sequenceEnd:   [
        {
            func: "{testEnvironment}.pouchDb.destroyPouch"
        },
        {
            event:    "{testEnvironment}.pouchDb.events.onDestroyPouchComplete",
            listener: "jqUnit.assertLeftHand",
            args:     ["The database should be destroyed on test completion...", { ok: true}, "{arguments}.0"]
        }
    ]
});

fluid.defaults("gpii.tests.pouchdb.component.common.caseHolder", {
    gradeNames: ["gpii.tests.pouchdb.component.common.caseHolder.base"],
    inputs: {
        bulkData: [
            {
                "_id": "one",
                "saying": "is the loneliest number"
            },
            {
                "_id": "two",
                "saying": "are required to tango"
            }
        ],
        mapReduce: [
            {
                "color": "red",
                "name": "strawberry"
            },
            {
                "color": "yellow",
                "name": "banana"
            },
            {
                "color": "red",
                "name": "cherry"
            },
            {
                "color": "blue",
                "name": "blueberry"
            },
            {
                name: "colorless glass noodles"
            }
        ]
    },
    expectedResponses: {
        bulkCreate: [{ ok: true, id: "one"}, { ok: true, id: "two"}]
    },
    rawModules: [{
        name: "Common tests for `gpii.pouch` component...",
        type: "test",
        tests: [
            {
                name: "Test the `info` method...",
                sequence: [
                    {
                        func: "{testEnvironment}.pouchDb.info"
                    },
                    {
                        event:    "{testEnvironment}.pouchDb.events.onInfoComplete",
                        listener: "jqUnit.assertLeftHand",
                        args:     ["The database info should be as expected...", { db_name: "test", doc_count: 0, update_seq: 0}, "{arguments}.0"]
                    }
                ]
            },
            {
                name: "Test the `POST` method (with an ID)...",
                sequence: [
                    {
                        func: "{testEnvironment}.pouchDb.post",
                        args: [{ _id: "foo"}]
                    },
                    {
                        event: "{testEnvironment}.pouchDb.events.onPostComplete",
                        listener: "jqUnit.assertLeftHand",
                        args: ["The POST should have been successful...", { ok: true, id: "foo"}, "{arguments}.0"]
                    }
                ]
            },
            {
                name: "Test the `GET` method (with a non-existent ID)...",
                sequence: [
                    {
                        func: "{testEnvironment}.pouchDb.get",
                        args: [{ _id: "notGonnaFindIt"}]
                    },
                    {
                        event: "{testEnvironment}.pouchDb.events.onError",
                        listener: "jqUnit.assert",
                        args: ["An error should be thrown if a record cannot be found..."]
                    }
                ]
            },
            {
                name: "Test the `PUT` method (with an ID)...",
                sequence: [
                    {
                        func: "{testEnvironment}.pouchDb.post",
                        args: [{ _id: "bar"}]
                    },
                    {
                        event: "{testEnvironment}.pouchDb.events.onPostComplete",
                        listener: "jqUnit.assertLeftHand",
                        args: ["The PUT should have been successful...", { ok: true, id: "bar"}, "{arguments}.0"]
                    }
                ]
            },
            {
                name: "Test the `POST` method (without an ID)...",
                sequence: [
                    {
                        func: "{testEnvironment}.pouchDb.post",
                        args: [{ "onions": "raw" }]
                    },
                    {
                        event: "{testEnvironment}.pouchDb.events.onPostComplete",
                        listener: "{testEnvironment}.pouchDb.get",
                        args: ["{arguments}.0.id"]
                    },
                    {
                        event: "{testEnvironment}.pouchDb.events.onGetComplete",
                        listener: "jqUnit.assertLeftHand",
                        args: ["The record should have been POSTed...", { "onions": "raw"}, "{arguments}.0"]
                    }
                ]
            },
            {
                name: "Test the `bulkDocs` function...",
                sequence: [
                    {
                        func: "{testEnvironment}.pouchDb.bulkDocs",
                        args: ["{that}.options.inputs.bulkData"]
                    },
                    {
                        event:    "{testEnvironment}.pouchDb.events.onBulkDocsComplete",
                        listener: "gpii.test.pouchdb.recordsAreEquivalent",
                        args:     ["The bulk creation of documents should have been successful...", "{that}.options.expectedResponses.bulkCreate", "{arguments}.0"]
                    }
                ]
            },
            {
                name: "Test the `allDocs` function...",
                sequence: [
                    {
                        func: "{testEnvironment}.pouchDb.bulkDocs",
                        args: ["{that}.options.inputs.bulkData"]
                    },
                    {
                        event:    "{testEnvironment}.pouchDb.events.onBulkDocsComplete",
                        listener: "{testEnvironment}.pouchDb.allDocs",
                        args:     []
                    },
                    {
                        event:    "{testEnvironment}.pouchDb.events.onAllDocsComplete",
                        listener: "jqUnit.assertLeftHand",
                        args:     ["The bulk retrieval of all documents should return the correct number of records...", { offset: 0, total_rows: 2 }, "{arguments}.0"]
                    }
                ]
            },
            {
                name: "Test the `bulkGet` function...",
                sequence: [
                    {
                        func: "{testEnvironment}.pouchDb.bulkDocs",
                        args: ["{that}.options.inputs.bulkData"]
                    },
                    {
                        event:    "{testEnvironment}.pouchDb.events.onBulkDocsComplete",
                        listener: "{testEnvironment}.pouchDb.bulkGet",
                        args:     [{ docs: [{ id: "one" }, { id: "two"}]}]
                    },
                    {
                        event:    "{testEnvironment}.pouchDb.events.onBulkGetComplete",
                        listener: "gpii.test.pouchdb.recordsAreEquivalent",
                        args:     ["a bulk get of all documents should return the correct content...", [{ id: "one" }, { id: "two"}], "{arguments}.0.results"]
                    }
                ]
            },
            {
                name: "Test the `remove` function...",
                sequence: [
                    {
                        func: "{testEnvironment}.pouchDb.bulkDocs",
                        args: ["{that}.options.inputs.bulkData"]
                    },
                    {
                        event:    "{testEnvironment}.pouchDb.events.onBulkDocsComplete",
                        listener: "{testEnvironment}.pouchDb.get",
                        args:     ["two"]
                    },
                    {
                        event:    "{testEnvironment}.pouchDb.events.onGetComplete",
                        listener: "{testEnvironment}.pouchDb.remove",
                        args:     ["{arguments}.0"]
                    },
                    {
                        event:    "{testEnvironment}.pouchDb.events.onRemoveComplete",
                        listener: "{testEnvironment}.pouchDb.info",
                        args:     []
                    },
                    {
                        event:    "{testEnvironment}.pouchDb.events.onInfoComplete",
                        listener: "jqUnit.assertLeftHand",
                        args:     ["The database should now only contain one record...", { db_name: "test", doc_count: 1 }, "{arguments}.0"]
                    }
                ]
            },
            {
                name: "Test the `remove` method (with a non-existent ID)...",
                sequence: [
                    {
                        func: "{testEnvironment}.pouchDb.remove",
                        args: [{ _id: "notGonnaFindIt"}]
                    },
                    {
                        event: "{testEnvironment}.pouchDb.events.onError",
                        listener: "jqUnit.assert",
                        args: ["An error should be thrown if a record cannot be found..."]
                    }
                ]
            },
            {
                name: "Testing `query` handling (passing a single map function)...",
                sequence: [
                    {
                        func: "{testEnvironment}.pouchDb.bulkDocs",
                        args: ["{that}.options.inputs.mapReduce"]
                    },
                    {
                        event:    "{testEnvironment}.pouchDb.events.onBulkDocsComplete",
                        listener: "{testEnvironment}.pouchDb.query",
                        args:     [gpii.tests.pouchdb.component.common.map]
                    },
                    {
                        event:    "{testEnvironment}.pouchDb.events.onQueryComplete",
                        listener: "jqUnit.assertEquals",
                        args:     ["The view should return the right number of records...", 4, "{arguments}.0.rows.length" ]
                    }
                ]
            },
            {
                name: "Testing `query` handling (passing a map function as part of a JSON document)...",
                sequence: [
                    {
                        func: "{testEnvironment}.pouchDb.bulkDocs",
                        args: ["{that}.options.inputs.mapReduce"]
                    },
                    {
                        event:    "{testEnvironment}.pouchDb.events.onBulkDocsComplete",
                        listener: "{testEnvironment}.pouchDb.query",
                        args:     [{ map: gpii.tests.pouchdb.component.common.map}]
                    },
                    {
                        event:    "{testEnvironment}.pouchDb.events.onQueryComplete",
                        listener: "jqUnit.assertEquals",
                        args:     ["The view should return the right number of records...", 4, "{arguments}.0.rows.length" ]
                    }
                ]
            },
            {
                name: "Testing `query` handling (passing both map and reduce function)...",
                sequence: [
                    {
                        func: "{testEnvironment}.pouchDb.bulkDocs",
                        args: ["{that}.options.inputs.mapReduce"]
                    },
                    {
                        event:    "{testEnvironment}.pouchDb.events.onBulkDocsComplete",
                        listener: "{testEnvironment}.pouchDb.query",
                        args:     [{ map: gpii.tests.pouchdb.component.common.map, reduce: gpii.tests.pouchdb.component.common.reduce}]
                    },
                    {
                        event:    "{testEnvironment}.pouchDb.events.onQueryComplete",
                        listener: "jqUnit.assertDeepEq",
                        args:     ["The reduced data should be correct...", { red: 2, yellow: 1, blue: 1 }, "{arguments}.0.rows.0.value" ]
                    }
                ]
            }
        ]
    }]
});

fluid.defaults("gpii.tests.pouchdb.component.common.environment", {
    gradeNames: ["fluid.test.testEnvironment"],
    events: {
        constructFixtures: null
    },
    components: {
        pouchDb: {
            type: "gpii.pouch",
            createOnEvent: "constructFixtures",
            options: {
                dbOptions: {
                    name: "test"
                }
            }
        },
        caseHolder: {
            type: "gpii.tests.pouchdb.component.common.caseHolder"
        }
    }
});
<|endoftext|>


<commit_before>var M = require('./m');

var win = window;
// 状态缓存
var stateCache = {};
// url缓存
var urlCache = [];

// 得到basepath
var parseBasePath = function(path) {
	path = path.replace(/[^\/]+$/, '');
	return ('/' + path + '/').replace(/^\/+|\/+$/g, '/');
};
// 默认base path
var defBase = M.document.getElementsByTagName('base');
if (defBase && defBase.length) {
	defBase = parseBasePath(defBase[0].getAttribute('href'));
} else {
	defBase = '/';
}

var locationObj = M.parseLocation();
var locationPath = locationObj.pathname;
var locationOrigin = locationObj.origin;

var history = win.history;
var agent = (win.navigator || {}).userAgent;
if (!agent) agent = '';
var android = parseInt((/android (\d+)/.exec(agent.toLowerCase()) || [])[1], 10);
if (isNaN(android)) android = undefined;
var boxee = /Boxee/i.test(agent);

var supportPushState = !!(history && history.pushState && history.replaceState && !(android < 4) && !boxee);
var supportHashChange = !!('onhashchange' in win);

var MODE_MAP = {
		hashbang: 1,
		history: 2,
		abstract: 3
};

var hashbangPrefix = '#!';

var hashCacheState = '';

var History = {

	mode: MODE_MAP.hashbang,

	supportPushState: supportPushState,
	supportHashChange: supportHashChange,
	/*是否支持*/
	support: supportPushState || supportHashChange,

	/*是否已启动*/
	startd: false,

	/*在urlCache中位置*/
	index: -1,
	preIndex: -1,

	/*base path*/
	base: defBase,

	checkMode: function() {
		if (this.options.hashbang) {
			this.mode = MODE_MAP.hashbang;
		} else if (this.options.history) {
			this.mode = MODE_MAP.history;
		} else if (this.options.abstract) {
			this.mode = MODE_MAP.abstract;
		} else {
			// 默认 hashbang
			this.mode = MODE_MAP.hashbang;
		}
		if (this.mode === MODE_MAP.history && !this.supportPushState) {
			// history 模式 但是不支持 pushstate
			this.mode = MODE_MAP.hashbang;
		}
		if (!this.support) {
			// 都不支持
			this.mode = MODE_MAP.abstract;
		}
	},

	/**
	 * 启动
	 * @param  {Object} options 配置参数
	 */
	start: function(options) {
		if (this.startd) return;
		if (!options) options = {};
		var base = options.base;
		if (M.isDefined(base) && M.isString(base)) {
			this.base = parseBasePath(base);
		}
		this.startd = true;

		this.options = M.extend({}, options);

		// 检查设置的模式
		this.checkMode();

		this.pathExt = History.getPath(locationPath).slice(1);

		// 根据模式做处理
		switch (this.mode) {
			case MODE_MAP.history:
				win.addEventListener('popstate', this.onChange);
				break;
			case MODE_MAP.hashbang:
				win.addEventListener('hashchange', this.onChange);
				break;
			case MODE_MAP.abstract:
				break;
		}
		M.document.addEventListener('click', this.onDocClick);

		// 需要初始化一次当前的state
		this.onChange();
		this.trigger('inited');
	},

	/**
	 * 停止监听
	 */
	stop: function() {
		switch (this.mode) {
			case MODE_MAP.history:
				win.removeEventListener('popstate', this.onChange);
				break;
			case MODE_MAP.hashbang:
				win.removeEventListener('hashchange', this.onChange);
				break;
			case MODE_MAP.abstract:
				break;
		}
		M.document.removeEventListener('click', this.onDocClick);
		this.startd = false;
		this.index = -1;
		stateCache = {};
		urlCache = [];
	},

	/**
	 * 去掉url中base之后的path
	 * @param  {String}  url      url
	 * @param  {Boolean} noSearch 不加search信息
	 * @return {String}           去掉base之后的URL
	 */
	getPath: function(url, noSearch) {
		var urlDetail = M.parseUrl(url);
		var path = decodeURIComponent(urlDetail.pathname + (noSearch ? '' : urlDetail.search));
		// 去掉最后/
		var root = this.base.slice(0, -1);
		if (!path.indexOf(root)) path = path.slice(root.length);
		path = path.slice(1);
		if (path || History.base) {
			if (!path || path !== '/') {
				path = '/' + (path || '');
			}
		}
		return path;
	},

	/**
	 * document点击的事件处理函数
	 * @param  {Event}   e 事件对象
	 * @return {Boolean}   是否被阻止了
	 */
	onDocClick: function(e) {
		if (e.which > 1 || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) {
			return true;
		}

		var targetEle = e.target;
		var hrefTarget = M.getHrefAndTarget(targetEle);
		targetEle = hrefTarget.target;
		var href = hrefTarget.href;
		if (!href || !targetEle) {
			return;
		}
		// 存在 href 且和当前是同源
		// 且不带 target download rel!=external 且不是以 javascript: 开头
		var noSpes = !targetEle.target && !targetEle.hasAttribute('download') && targetEle.getAttribute('rel') !== 'external';
		if (History.checkUrl(href) && noSpes) {
			var datasetObj =  M.getDatesetObj(targetEle);
			var state = History.createStateObject(href, datasetObj);
			e.preventDefault();
			History.pushState(state, true);
			return false;
		}
	},

	/**
	 * 检测url是否可以走自定义pushState
	 * @param  {String}  url       url
	 * @param  {String}  urlOrigin 检测url的origin
	 * @return {Boolean}           检测结果
	 */
	checkUrl: function(url, urlOrigin) {
		if (!urlOrigin) {
			urlOrigin = M.parseUrl(url).origin;
		}
		var rext = /^(javascript:)|(mailto:)|(tel:)/;
		return url && locationOrigin === urlOrigin && !rext.test(url);
	},

	/**
	 * 添加新的url
	 * @param  {String}      url  新的url
	 * @param  {Object|Null} data 附加数据
	 */
	push: function(url, data) {
		var state = this.createStateObject(url, data);
		this.pushState(state);
	},

	currentHref: function() {
		return M.location.href.replace(History.pathExt, '').replace(hashbangPrefix + '/', '');
	},

	/**
	 * 添加新的state
	 * @param  {Object}  state   state数据对象
	 * @param  {Boolean} checked 是否已经校验过该state
	 */
	pushState: function(state, checked) {
		if (!checked && !this.checkUrl(state.url, state.origin)) return;
		if (state.url === History.getCurrentState().url) return;
		// 如果是允许改变history 且其dataset中不包含href的话才会改变history
		// 规则就是：
		// data-href="newUrl"会被认为是在当前页中切换，也就是局部禁用pushstate
		if (this.mode !== MODE_MAP.abstract && state.url !== History.currentHref()) {
			if (this.mode === MODE_MAP.hashbang) {
				if (M.isUndefined(state.data.href)) {
					hashCacheState = state;
					M.location.hash = hashbangPrefix + state.rpath;
					return;
				}
			} else {
				M.isUndefined(state.data.href) && history[state.replace ? 'replaceState' : 'pushState'](state, state.title, state.url);
			}
		}
		this.onChange({
			state: state
		});
	},

	/**
	 * history改变回调
	 */
	onChange: function(e) {
		if (e && e.type === 'hashchange') {
			e.state = hashCacheState;
		}
		var state = e && e.state || History.getUrlState(History.currentHref());
		var oldState = History.getCurrentState();

		hashCacheState = null;

		// 如果新的url和旧的url只是hash不同，那么应该走scrollIntoView
		var scrollToEle;
		if (oldState && state.rurl === oldState.rurl) {
			if (e.type !== 'popstate' && state.hash) {
				scrollToEle = M.document.getElementById(state.hash);
				scrollToEle && scrollToEle.scrollIntoView();
			}
			return;
		}

		var newIndex = History.storeState(state);
		var type = '';
		if (newIndex > History.index) {
			// 可以认为是往前 不管是新的 还是已经存在的
			type = 'forward';
		} else if (newIndex < History.index) {
			// 后退
			type = 'back';
		} else {
			e.preventDefault();
			return false;
		}

		// 对于 有data-rel 是back的 调整其顺序
		// 一般的场景就是 类似 返回按钮
		if (type !== 'back' && state.data.rel === 'back') {
			type = 'back';
		} else if (type === 'back' && state.data.rel !== 'back' && oldState.data.rel === 'back') {
			type = 'forward';
		}
		M.document.title = state.title;
		if (newIndex !== History.index) {
			History.preIndex = History.index;
		}
		History.index = newIndex;
		// 触发改变事件
		History.trigger(type, state, oldState);
		History.trigger('change', type, state, oldState);
	},

	/**
	 * 得到url的state 如果不存在则创建新的
	 * @param  {String} url url
	 * @return {Object}     包装的state对象
	 */
	getUrlState: function(url) {
		url = M.getFullUrl(url);
		return stateCache[url] || this.createStateObject(url);
	},

	/**
	 * 得到当前的state
	 * @return {Object|Null} 当前的state
	 */
	getCurrentState: function() {
		var url = urlCache[this.index];
		if (!url) return null;
		return stateCache[url] || null;
	},

	/**
	 * 得到上一个状态
	 * @return {Object|Null} 当前的state
	 */
	getPrevState: function() {
		var url = urlCache[History.preIndex];
		if (!url) {
			url = urlCache[this.index - 1];
			if (!url) {
				return null;
			}
		}
		return stateCache[url] || null;
	},

	/**
	 * 创建包装state对象
	 * @param  {String} url   url
	 * @param  {object} data  附带数据
	 * @return {Object}       包装的state对象
	 */
	createStateObject: function(url, data) {
		if (url) {
			if (url.charAt(0) === '/') {
				url = url.slice(1);
				url = this.base + url;
			}
		} else {
			url = History.currentHref();
		}
		var parsedUrl = M.parseUrl(url);
		return {
			data: data || (data = {}),
			title: data.title || M.document.title,
			rurl: parsedUrl.rurl,
			url: parsedUrl.url,
			path: parsedUrl.pathname,
			rpath: History.getPath(url),
			origin: parsedUrl.origin,
			hash: parsedUrl.hash,
			replace: M.isString(data.replace) ? data.replace === 'true' : !!data.replace
		};
	},

	/**
	 * url是否在缓存中
	 * @param  {String}  url url
	 * @return {Boolean}     是否在缓存中
	 */
	hasUrl: function(url) {
		return !!stateCache[url];
	},

	/**
	 * 存储state
	 * @param  {Object}            state 包装state对象
	 * @return {Number}            在urlCache中位置
	 */
	storeState: function(state) {
		var i = -1;
		var url = state.rurl;
		var toIndex = urlCache.indexOf(url);
		if (this.hasUrl(url)) {
			// 之前有
			i = toIndex;
		} else {
			i = this.index + 1;
			urlCache.splice(i, 0, url);
		}
		stateCache[url] = M.extend(true, stateCache[url], state);
		this.clearCache(i);
		return i;
	},

	/**
	 * 清除指定位置之后的cache
	 * @param  {Number} index 指定位置
	 */
	clearCache: function(index) {
		if (M.isUndefined(index)) index = -1;
		// 最多保留50条记录
		var num = index + 50;
		var clearUrls = urlCache.slice(num);
		clearUrls.forEach(function(url) {
			delete stateCache[url];
		});
		if (urlCache.length > num) urlCache.length = num;
	},

	/**
	 * 得到缓存信息
	 * @return {Object} 缓存
	 */
	getCache: function() {
		return {
			urlCache: urlCache,
			stateCache: stateCache
		};
	},

	parseUrl: parseUrl
};

// 增加事件机制
M.extendByBase(History);

M.history = History;

module.exports = M;

function parseUrl(url) {
	var path = History.getPath(url);
	// 如果path为空 但是有base 说明 可以path为/
	if (path) {
		return M.parseQuery(path);
	}
	return null;
}
<commit_msg>fix rext regexp<commit_after>var M = require('./m');

var win = window;
// 状态缓存
var stateCache = {};
// url缓存
var urlCache = [];

// 得到basepath
var parseBasePath = function(path) {
	path = path.replace(/[^\/]+$/, '');
	return ('/' + path + '/').replace(/^\/+|\/+$/g, '/');
};
// 默认base path
var defBase = M.document.getElementsByTagName('base');
if (defBase && defBase.length) {
	defBase = parseBasePath(defBase[0].getAttribute('href'));
} else {
	defBase = '/';
}

var locationObj = M.parseLocation();
var locationPath = locationObj.pathname;
var locationOrigin = locationObj.origin;

var history = win.history;
var agent = (win.navigator || {}).userAgent;
if (!agent) agent = '';
var android = parseInt((/android (\d+)/.exec(agent.toLowerCase()) || [])[1], 10);
if (isNaN(android)) android = undefined;
var boxee = /Boxee/i.test(agent);

var supportPushState = !!(history && history.pushState && history.replaceState && !(android < 4) && !boxee);
var supportHashChange = !!('onhashchange' in win);

var MODE_MAP = {
		hashbang: 1,
		history: 2,
		abstract: 3
};

var hashbangPrefix = '#!';

var hashCacheState = '';

var History = {

	mode: MODE_MAP.hashbang,

	supportPushState: supportPushState,
	supportHashChange: supportHashChange,
	/*是否支持*/
	support: supportPushState || supportHashChange,

	/*是否已启动*/
	startd: false,

	/*在urlCache中位置*/
	index: -1,
	preIndex: -1,

	/*base path*/
	base: defBase,

	checkMode: function() {
		if (this.options.hashbang) {
			this.mode = MODE_MAP.hashbang;
		} else if (this.options.history) {
			this.mode = MODE_MAP.history;
		} else if (this.options.abstract) {
			this.mode = MODE_MAP.abstract;
		} else {
			// 默认 hashbang
			this.mode = MODE_MAP.hashbang;
		}
		if (this.mode === MODE_MAP.history && !this.supportPushState) {
			// history 模式 但是不支持 pushstate
			this.mode = MODE_MAP.hashbang;
		}
		if (!this.support) {
			// 都不支持
			this.mode = MODE_MAP.abstract;
		}
	},

	/**
	 * 启动
	 * @param  {Object} options 配置参数
	 */
	start: function(options) {
		if (this.startd) return;
		if (!options) options = {};
		var base = options.base;
		if (M.isDefined(base) && M.isString(base)) {
			this.base = parseBasePath(base);
		}
		this.startd = true;

		this.options = M.extend({}, options);

		// 检查设置的模式
		this.checkMode();

		this.pathExt = History.getPath(locationPath).slice(1);

		// 根据模式做处理
		switch (this.mode) {
			case MODE_MAP.history:
				win.addEventListener('popstate', this.onChange);
				break;
			case MODE_MAP.hashbang:
				win.addEventListener('hashchange', this.onChange);
				break;
			case MODE_MAP.abstract:
				break;
		}
		M.document.addEventListener('click', this.onDocClick);

		// 需要初始化一次当前的state
		this.onChange();
		this.trigger('inited');
	},

	/**
	 * 停止监听
	 */
	stop: function() {
		switch (this.mode) {
			case MODE_MAP.history:
				win.removeEventListener('popstate', this.onChange);
				break;
			case MODE_MAP.hashbang:
				win.removeEventListener('hashchange', this.onChange);
				break;
			case MODE_MAP.abstract:
				break;
		}
		M.document.removeEventListener('click', this.onDocClick);
		this.startd = false;
		this.index = -1;
		stateCache = {};
		urlCache = [];
	},

	/**
	 * 去掉url中base之后的path
	 * @param  {String}  url      url
	 * @param  {Boolean} noSearch 不加search信息
	 * @return {String}           去掉base之后的URL
	 */
	getPath: function(url, noSearch) {
		var urlDetail = M.parseUrl(url);
		var path = decodeURIComponent(urlDetail.pathname + (noSearch ? '' : urlDetail.search));
		// 去掉最后/
		var root = this.base.slice(0, -1);
		if (!path.indexOf(root)) path = path.slice(root.length);
		path = path.slice(1);
		if (path || History.base) {
			if (!path || path !== '/') {
				path = '/' + (path || '');
			}
		}
		return path;
	},

	/**
	 * document点击的事件处理函数
	 * @param  {Event}   e 事件对象
	 * @return {Boolean}   是否被阻止了
	 */
	onDocClick: function(e) {
		if (e.which > 1 || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) {
			return true;
		}

		var targetEle = e.target;
		var hrefTarget = M.getHrefAndTarget(targetEle);
		targetEle = hrefTarget.target;
		var href = hrefTarget.href;
		if (!href || !targetEle) {
			return;
		}
		// 存在 href 且和当前是同源
		// 且不带 target download rel!=external 且不是以 javascript: 开头
		var noSpes = !targetEle.target && !targetEle.hasAttribute('download') && targetEle.getAttribute('rel') !== 'external';
		if (History.checkUrl(href) && noSpes) {
			var datasetObj =  M.getDatesetObj(targetEle);
			var state = History.createStateObject(href, datasetObj);
			e.preventDefault();
			History.pushState(state, true);
			return false;
		}
	},

	/**
	 * 检测url是否可以走自定义pushState
	 * @param  {String}  url       url
	 * @param  {String}  urlOrigin 检测url的origin
	 * @return {Boolean}           检测结果
	 */
	checkUrl: function(url, urlOrigin) {
		if (!urlOrigin) {
			urlOrigin = M.parseUrl(url).origin;
		}
		var rext = /^(javascript|mailto|tel):/;
		return url && locationOrigin === urlOrigin && !rext.test(url);
	},

	/**
	 * 添加新的url
	 * @param  {String}      url  新的url
	 * @param  {Object|Null} data 附加数据
	 */
	push: function(url, data) {
		var state = this.createStateObject(url, data);
		this.pushState(state);
	},

	currentHref: function() {
		return M.location.href.replace(History.pathExt, '').replace(hashbangPrefix + '/', '');
	},

	/**
	 * 添加新的state
	 * @param  {Object}  state   state数据对象
	 * @param  {Boolean} checked 是否已经校验过该state
	 */
	pushState: function(state, checked) {
		if (!checked && !this.checkUrl(state.url, state.origin)) return;
		if (state.url === History.getCurrentState().url) return;
		// 如果是允许改变history 且其dataset中不包含href的话才会改变history
		// 规则就是：
		// data-href="newUrl"会被认为是在当前页中切换，也就是局部禁用pushstate
		if (this.mode !== MODE_MAP.abstract && state.url !== History.currentHref()) {
			if (this.mode === MODE_MAP.hashbang) {
				if (M.isUndefined(state.data.href)) {
					hashCacheState = state;
					M.location.hash = hashbangPrefix + state.rpath;
					return;
				}
			} else {
				M.isUndefined(state.data.href) && history[state.replace ? 'replaceState' : 'pushState'](state, state.title, state.url);
			}
		}
		this.onChange({
			state: state
		});
	},

	/**
	 * history改变回调
	 */
	onChange: function(e) {
		if (e && e.type === 'hashchange') {
			e.state = hashCacheState;
		}
		var state = e && e.state || History.getUrlState(History.currentHref());
		var oldState = History.getCurrentState();

		hashCacheState = null;

		// 如果新的url和旧的url只是hash不同，那么应该走scrollIntoView
		var scrollToEle;
		if (oldState && state.rurl === oldState.rurl) {
			if (e.type !== 'popstate' && state.hash) {
				scrollToEle = M.document.getElementById(state.hash);
				scrollToEle && scrollToEle.scrollIntoView();
			}
			return;
		}

		var newIndex = History.storeState(state);
		var type = '';
		if (newIndex > History.index) {
			// 可以认为是往前 不管是新的 还是已经存在的
			type = 'forward';
		} else if (newIndex < History.index) {
			// 后退
			type = 'back';
		} else {
			e.preventDefault();
			return false;
		}

		// 对于 有data-rel 是back的 调整其顺序
		// 一般的场景就是 类似 返回按钮
		if (type !== 'back' && state.data.rel === 'back') {
			type = 'back';
		} else if (type === 'back' && state.data.rel !== 'back' && oldState.data.rel === 'back') {
			type = 'forward';
		}
		M.document.title = state.title;
		if (newIndex !== History.index) {
			History.preIndex = History.index;
		}
		History.index = newIndex;
		// 触发改变事件
		History.trigger(type, state, oldState);
		History.trigger('change', type, state, oldState);
	},

	/**
	 * 得到url的state 如果不存在则创建新的
	 * @param  {String} url url
	 * @return {Object}     包装的state对象
	 */
	getUrlState: function(url) {
		url = M.getFullUrl(url);
		return stateCache[url] || this.createStateObject(url);
	},

	/**
	 * 得到当前的state
	 * @return {Object|Null} 当前的state
	 */
	getCurrentState: function() {
		var url = urlCache[this.index];
		if (!url) return null;
		return stateCache[url] || null;
	},

	/**
	 * 得到上一个状态
	 * @return {Object|Null} 当前的state
	 */
	getPrevState: function() {
		var url = urlCache[History.preIndex];
		if (!url) {
			url = urlCache[this.index - 1];
			if (!url) {
				return null;
			}
		}
		return stateCache[url] || null;
	},

	/**
	 * 创建包装state对象
	 * @param  {String} url   url
	 * @param  {object} data  附带数据
	 * @return {Object}       包装的state对象
	 */
	createStateObject: function(url, data) {
		if (url) {
			if (url.charAt(0) === '/') {
				url = url.slice(1);
				url = this.base + url;
			}
		} else {
			url = History.currentHref();
		}
		var parsedUrl = M.parseUrl(url);
		return {
			data: data || (data = {}),
			title: data.title || M.document.title,
			rurl: parsedUrl.rurl,
			url: parsedUrl.url,
			path: parsedUrl.pathname,
			rpath: History.getPath(url),
			origin: parsedUrl.origin,
			hash: parsedUrl.hash,
			replace: M.isString(data.replace) ? data.replace === 'true' : !!data.replace
		};
	},

	/**
	 * url是否在缓存中
	 * @param  {String}  url url
	 * @return {Boolean}     是否在缓存中
	 */
	hasUrl: function(url) {
		return !!stateCache[url];
	},

	/**
	 * 存储state
	 * @param  {Object}            state 包装state对象
	 * @return {Number}            在urlCache中位置
	 */
	storeState: function(state) {
		var i = -1;
		var url = state.rurl;
		var toIndex = urlCache.indexOf(url);
		if (this.hasUrl(url)) {
			// 之前有
			i = toIndex;
		} else {
			i = this.index + 1;
			urlCache.splice(i, 0, url);
		}
		stateCache[url] = M.extend(true, stateCache[url], state);
		this.clearCache(i);
		return i;
	},

	/**
	 * 清除指定位置之后的cache
	 * @param  {Number} index 指定位置
	 */
	clearCache: function(index) {
		if (M.isUndefined(index)) index = -1;
		// 最多保留50条记录
		var num = index + 50;
		var clearUrls = urlCache.slice(num);
		clearUrls.forEach(function(url) {
			delete stateCache[url];
		});
		if (urlCache.length > num) urlCache.length = num;
	},

	/**
	 * 得到缓存信息
	 * @return {Object} 缓存
	 */
	getCache: function() {
		return {
			urlCache: urlCache,
			stateCache: stateCache
		};
	},

	parseUrl: parseUrl
};

// 增加事件机制
M.extendByBase(History);

M.history = History;

module.exports = M;

function parseUrl(url) {
	var path = History.getPath(url);
	// 如果path为空 但是有base 说明 可以path为/
	if (path) {
		return M.parseQuery(path);
	}
	return null;
}
<|endoftext|>


<commit_before>/**
* Copyright (c) Microsoft.  All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

var fs = require('fs');
var path = require('path');
var utils = require('../../utils');

var isWindows = process.platform === 'win32'

// Making sure this works on node 0.6.20 as well as 0.8
fs.existsSync = fs.existsSync || path.existsSync;
path.sep = path.sep || (isWindows ? '\\' : '/');

var templatesDir = __dirname;
var log = { info: function () { } };
var confirm = function () { return false; };

var ScriptType = {
  batch: 'BATCH',
  bash: 'BASH'
};

var ProjectType = {
  wap: 'WAP',
  website: 'WEBSITE',
  node: 'NODE',
  basic: 'BASIC'
}

exports.ScriptType = ScriptType;
exports.ProjectType = ProjectType;

function ScriptGenerator(repositoryRoot, projectType, projectPath, solutionPath, sitePath, scriptType, noDotDeployment, noSolution, logger, confirmFunc) {
  argNotNull(repositoryRoot, 'repositoryRoot');
  argNotNull(projectType, 'projectType');
  argNotNull(scriptType, 'scriptType');
  argNotNull(sitePath, 'sitePath');

  scriptType = scriptType.toUpperCase();
  if (scriptType !== ScriptType.batch && scriptType !== ScriptType.bash) {
    throw new Error('Script type should be either batch or bash');
  }
  this.scriptType = scriptType;

  log = logger || log;
  confirm = confirmFunc || confirm;

  if (projectPath) {
    if (!isPathSubDir(repositoryRoot, projectPath)) {
      throw new Error('The project file path should be a sub-directory of the repository root');
    }

    var relativeProjectPath = path.relative(repositoryRoot, projectPath);
    log.info('Project file path: .' + path.sep + relativeProjectPath);
    this.projectPath = relativeProjectPath;
  }

  if (solutionPath) {
    if (!isPathSubDir(repositoryRoot, solutionPath)) {
      throw new Error('The solution file path should be the same as repository root or a sub-directory of it.');
    }

    var relativeSolutionPath = path.relative(repositoryRoot, solutionPath);
    log.info('Solution file path: .' + path.sep + relativeSolutionPath);
    this.solutionPath = relativeSolutionPath;
  }

  if (!isPathSubDir(repositoryRoot, sitePath)) {
    throw new Error('The site directory path should be the same as repository root or a sub-directory of it.');
  }

  var relativeSitePath = path.relative(repositoryRoot, sitePath);
  if (relativeSitePath) {
    relativeSitePath = path.sep + relativeSitePath;
    log.info('The site directory path: .' + relativeSitePath);
  }
  this.sitePath = relativeSitePath || '';

  projectType = projectType.toUpperCase();

  this.repositoryRoot = repositoryRoot;
  this.projectType = projectType;
  this.noDotDeployment = noDotDeployment;
  this.noSolution = noSolution;
  this.absoluteSitePath = path.join(this.repositoryRoot, this.sitePath);

  this.generators = [];
  this.generators[ProjectType.wap] = generateWapDeploymentScript;
  this.generators[ProjectType.website] = generateWebSiteDeploymentScript;
  this.generators[ProjectType.node] = generateNodeDeploymentScript;
  this.generators[ProjectType.basic] = generateBasicWebSiteDeploymentScript;
}

function generateWapDeploymentScript(scriptGenerator, _) {
  scriptGenerator.generateWapDeploymentScript(_);
}

function generateWebSiteDeploymentScript(scriptGenerator, _) {
  scriptGenerator.generateWebSiteDeploymentScript(_);
}

function generateNodeDeploymentScript(scriptGenerator, _) {
  scriptGenerator.generateNodeDeploymentScript(_);
}

function generateBasicWebSiteDeploymentScript(scriptGenerator, _) {
  if (scriptGenerator.solutionPath) {
    throw new Error('Solution path is not supported with this website type');
  }
  scriptGenerator.generateWebSiteDeploymentScript(_);
}

ScriptGenerator.prototype.generateDeploymentScript = function (_) {
  var generator = this.generators[this.projectType];
  if (!generator) {
    throw new Error('Invalid project type received: ' + this.projectType);
  }

  generator(this, _);
}

function isPathSubDir(parentPath, childPath) {
  var relativePath = path.relative(parentPath, childPath);

  // The parent path is actually the parent of the child path if the result of path.relative:
  // a. Doesn't contain '..' at the start
  // b. Doesn't equal to the child path entirely
  return relativePath.indexOf('..') != 0
      && relativePath != path.resolve(childPath);
}

ScriptGenerator.prototype.generateNodeDeploymentScript = function (_) {
  log.info('Generating deployment script for node.js Web Site');

  createIisNodeWebConfigIfNeeded(this.absoluteSitePath);
  utils.copyIisNodeWhenServerJsPresent(log, this.absoluteSitePath, _);

  this.generateBasicDeploymentScript('node.template', _);
}

function getNodeStartFile(sitePath) {
  var nodeStartFiles = ['server.js', 'app.js'];

  for (var i in nodeStartFiles) {
    var nodeStartFilePath = path.join(sitePath, nodeStartFiles[i]);
    // TODO: Change to async and add retry
    if (fs.existsSync(nodeStartFilePath)) {
      return nodeStartFiles[i];
    }
  }

  return null;
}

function createIisNodeWebConfigIfNeeded(sitePath) {
  var webConfigPath = path.join(sitePath, 'web.config');

  if (!fs.existsSync(webConfigPath)) {
    log.info('Creating Web.config to enable Node.js activation.');

    var nodeStartFilePath = getNodeStartFile(sitePath);
    if (!nodeStartFilePath) {
      throw new Error('Missing server.js/app.js file which is required for a node.js site');
    }

    var webConfigContent = getTemplateContent('iisnode.config.template');
    webConfigContent =
        webConfigContent.replace(/{NodeStartFile}/g, fixPathSeperatorToWindows(nodeStartFilePath));
    writeContentToFile(webConfigPath, webConfigContent);
  }
}

ScriptGenerator.prototype.generateWapDeploymentScript = function (_) {
  argNotNull(this.projectPath, 'projectPath');

  if (this.scriptType != ScriptType.batch) {
    throw new Error('Only batch script files are supported for .NET Web Application');
  }

  if (!this.solutionPath && !this.noSolution) {
    throw new Error('Missing solution file path (--solutionPath), to explicitly not require a solution use the flag --no-solution');
  }

  log.info('Generating deployment script for .NET Web Application');

  var msbuildArguments = '"%DEPLOYMENT_SOURCE%\\' + this.projectPath + '" /nologo /verbosity:m /t:Build /t:pipelinePreDeployCopyAllFilesToOneFolder /p:_PackageTempDir="%DEPLOYMENT_TEMP%";AutoParameterizationWebConfigConnectionStrings=false;Configuration=Release';

  if (this.solutionPath != null) {
    var solutionDir = path.dirname(this.solutionPath);
    msbuildArguments += ' /p:SolutionDir="%DEPLOYMENT_SOURCE%\\' + solutionDir + '\\\\\"';
  }

    msbuildArguments += ' %SCM_BUILD_ARGS%';

  this.generateDotNetDeploymentScript('deploy.batch.aspnet.wap.template', msbuildArguments, _);
}

ScriptGenerator.prototype.generateWebSiteDeploymentScript = function (_) {
  if (this.solutionPath) {
    // Solution based website (.NET)
    log.info('Generating deployment script for .NET Web Site');

    if (this.scriptType != ScriptType.batch) {
      throw new Error('Only batch script files are supported for .NET Web Site');
    }

    var msbuildArguments = '"%DEPLOYMENT_SOURCE%\\' + fixPathSeperatorToWindows(this.solutionPath) + '" /verbosity:m /nologo %build_args%';
    this.generateDotNetDeploymentScript('deploy.batch.aspnet.website.template', msbuildArguments, _);
  } else {
    // Basic website
    log.info('Generating deployment script for Web Site');

    var packageJsonFilePath = path.join(this.absoluteSitePath, 'package.json');
    if (fs.existsSync(packageJsonFilePath)) {
      // On package.json, use node.template which will install npm packages
      this.generateBasicDeploymentScript('node.template', _);
    } else {
      // Otherwise it's a simple copy to deploy
      this.generateBasicDeploymentScript('basic.template', _);
    }
  }
}

ScriptGenerator.prototype.generateBasicDeploymentScript = function (templateFileName, _) {
  argNotNull(templateFileName, 'templateFileName');

  var lowerCaseScriptType = this.scriptType.toLowerCase();
  var fixedSitePath = this.scriptType === ScriptType.batch ? fixPathSeperatorToWindows(this.sitePath) : fixPathSeperatorToUnix(this.sitePath);
  var templateContent =
      getTemplatesContent([
          'deploy.' + lowerCaseScriptType + '.prefix.template',
          'deploy.' + lowerCaseScriptType + '.' + templateFileName,
          'deploy.' + lowerCaseScriptType + '.postfix.template'])
      .replace(/{SitePath}/g, fixedSitePath);

  this.writeDeploymentFiles(templateContent, _);
}

ScriptGenerator.prototype.generateDotNetDeploymentScript = function (templateFileName, msbuildArguments, _) {
  argNotNull(templateFileName, 'templateFileName');

  var templateContent =
        getTemplatesContent([
            'deploy.batch.prefix.template',
            'deploy.batch.aspnet.template',
            templateFileName,
            'deploy.batch.postfix.template'])
        .replace(/{MSBuildArguments}/g, msbuildArguments)
        .replace(/{SitePath}/g, fixPathSeperatorToWindows(this.sitePath));

  this.writeDeploymentFiles(templateContent, _);
}

function getTemplatesContent(fileNames) {
  var content = '';

  for (var i in fileNames) {
    content += getTemplateContent(fileNames[i]);
  }

  return content;
}

function fixPathSeperatorToWindows(pathStr) {
  return pathStr.replace(/\//g, '\\');
}

function fixPathSeperatorToUnix(pathStr) {
  return pathStr.replace(/\\/g, '/');
}

ScriptGenerator.prototype.writeDeploymentFiles = function (templateContent, _) {
  argNotNull(templateContent, 'templateContent');

  var deployScriptFileName;
  var deploymentCommand;
  if (this.scriptType == ScriptType.batch) {
    deployScriptFileName = 'deploy.cmd';
    deploymentCommand = deployScriptFileName;
  } else {
    deployScriptFileName = 'deploy.sh';
    deploymentCommand = 'bash ' + deployScriptFileName;
  }

  var deployScriptPath = path.join(this.repositoryRoot, deployScriptFileName);
  var deploymentFilePath = path.join(this.repositoryRoot, '.deployment');

  // Write the custom deployment script
  writeContentToFile(deployScriptPath, templateContent, _);

  if (!this.noDotDeployment) {
    // Write the .deployment file
    writeContentToFile(deploymentFilePath, '[config]\ncommand = ' + deploymentCommand, _);
  }

  log.info('Generated deployment script files');
}

function getTemplateContent(templateFileName) {
  return fs.readFileSync(getTemplatePath(templateFileName), 'utf8');
}

function getTemplatePath(fileName) {
  return path.join(templatesDir, fileName);
}

function writeContentToFile(path, content, _) {
  // TODO: Add check whether file exist
  if (fs.existsSync(path)) {
    if (!confirm('The file: "' + path + '" already exists\nAre you sure you want to overwrite it (y/n): ', _)) {
      // Do not overwrite the file
      return;
    }
  }

  fs.writeFile(path, content, _);
}

function argNotNull(arg, argName) {
  if (arg === null || arg === undefined) {
    throw new Error('The argument "' + argName + '" is null');
  }
}

exports.ScriptGenerator = ScriptGenerator;
<commit_msg>Fix missed build args<commit_after>/**
* Copyright (c) Microsoft.  All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

var fs = require('fs');
var path = require('path');
var utils = require('../../utils');

var isWindows = process.platform === 'win32'

// Making sure this works on node 0.6.20 as well as 0.8
fs.existsSync = fs.existsSync || path.existsSync;
path.sep = path.sep || (isWindows ? '\\' : '/');

var templatesDir = __dirname;
var log = { info: function () { } };
var confirm = function () { return false; };

var ScriptType = {
  batch: 'BATCH',
  bash: 'BASH'
};

var ProjectType = {
  wap: 'WAP',
  website: 'WEBSITE',
  node: 'NODE',
  basic: 'BASIC'
}

exports.ScriptType = ScriptType;
exports.ProjectType = ProjectType;

function ScriptGenerator(repositoryRoot, projectType, projectPath, solutionPath, sitePath, scriptType, noDotDeployment, noSolution, logger, confirmFunc) {
  argNotNull(repositoryRoot, 'repositoryRoot');
  argNotNull(projectType, 'projectType');
  argNotNull(scriptType, 'scriptType');
  argNotNull(sitePath, 'sitePath');

  scriptType = scriptType.toUpperCase();
  if (scriptType !== ScriptType.batch && scriptType !== ScriptType.bash) {
    throw new Error('Script type should be either batch or bash');
  }
  this.scriptType = scriptType;

  log = logger || log;
  confirm = confirmFunc || confirm;

  if (projectPath) {
    if (!isPathSubDir(repositoryRoot, projectPath)) {
      throw new Error('The project file path should be a sub-directory of the repository root');
    }

    var relativeProjectPath = path.relative(repositoryRoot, projectPath);
    log.info('Project file path: .' + path.sep + relativeProjectPath);
    this.projectPath = relativeProjectPath;
  }

  if (solutionPath) {
    if (!isPathSubDir(repositoryRoot, solutionPath)) {
      throw new Error('The solution file path should be the same as repository root or a sub-directory of it.');
    }

    var relativeSolutionPath = path.relative(repositoryRoot, solutionPath);
    log.info('Solution file path: .' + path.sep + relativeSolutionPath);
    this.solutionPath = relativeSolutionPath;
  }

  if (!isPathSubDir(repositoryRoot, sitePath)) {
    throw new Error('The site directory path should be the same as repository root or a sub-directory of it.');
  }

  var relativeSitePath = path.relative(repositoryRoot, sitePath);
  if (relativeSitePath) {
    relativeSitePath = path.sep + relativeSitePath;
    log.info('The site directory path: .' + relativeSitePath);
  }
  this.sitePath = relativeSitePath || '';

  projectType = projectType.toUpperCase();

  this.repositoryRoot = repositoryRoot;
  this.projectType = projectType;
  this.noDotDeployment = noDotDeployment;
  this.noSolution = noSolution;
  this.absoluteSitePath = path.join(this.repositoryRoot, this.sitePath);

  this.generators = [];
  this.generators[ProjectType.wap] = generateWapDeploymentScript;
  this.generators[ProjectType.website] = generateWebSiteDeploymentScript;
  this.generators[ProjectType.node] = generateNodeDeploymentScript;
  this.generators[ProjectType.basic] = generateBasicWebSiteDeploymentScript;
}

function generateWapDeploymentScript(scriptGenerator, _) {
  scriptGenerator.generateWapDeploymentScript(_);
}

function generateWebSiteDeploymentScript(scriptGenerator, _) {
  scriptGenerator.generateWebSiteDeploymentScript(_);
}

function generateNodeDeploymentScript(scriptGenerator, _) {
  scriptGenerator.generateNodeDeploymentScript(_);
}

function generateBasicWebSiteDeploymentScript(scriptGenerator, _) {
  if (scriptGenerator.solutionPath) {
    throw new Error('Solution path is not supported with this website type');
  }
  scriptGenerator.generateWebSiteDeploymentScript(_);
}

ScriptGenerator.prototype.generateDeploymentScript = function (_) {
  var generator = this.generators[this.projectType];
  if (!generator) {
    throw new Error('Invalid project type received: ' + this.projectType);
  }

  generator(this, _);
}

function isPathSubDir(parentPath, childPath) {
  var relativePath = path.relative(parentPath, childPath);

  // The parent path is actually the parent of the child path if the result of path.relative:
  // a. Doesn't contain '..' at the start
  // b. Doesn't equal to the child path entirely
  return relativePath.indexOf('..') != 0
      && relativePath != path.resolve(childPath);
}

ScriptGenerator.prototype.generateNodeDeploymentScript = function (_) {
  log.info('Generating deployment script for node.js Web Site');

  createIisNodeWebConfigIfNeeded(this.absoluteSitePath);
  utils.copyIisNodeWhenServerJsPresent(log, this.absoluteSitePath, _);

  this.generateBasicDeploymentScript('node.template', _);
}

function getNodeStartFile(sitePath) {
  var nodeStartFiles = ['server.js', 'app.js'];

  for (var i in nodeStartFiles) {
    var nodeStartFilePath = path.join(sitePath, nodeStartFiles[i]);
    // TODO: Change to async and add retry
    if (fs.existsSync(nodeStartFilePath)) {
      return nodeStartFiles[i];
    }
  }

  return null;
}

function createIisNodeWebConfigIfNeeded(sitePath) {
  var webConfigPath = path.join(sitePath, 'web.config');

  if (!fs.existsSync(webConfigPath)) {
    log.info('Creating Web.config to enable Node.js activation.');

    var nodeStartFilePath = getNodeStartFile(sitePath);
    if (!nodeStartFilePath) {
      throw new Error('Missing server.js/app.js file which is required for a node.js site');
    }

    var webConfigContent = getTemplateContent('iisnode.config.template');
    webConfigContent =
        webConfigContent.replace(/{NodeStartFile}/g, fixPathSeperatorToWindows(nodeStartFilePath));
    writeContentToFile(webConfigPath, webConfigContent);
  }
}

ScriptGenerator.prototype.generateWapDeploymentScript = function (_) {
  argNotNull(this.projectPath, 'projectPath');

  if (this.scriptType != ScriptType.batch) {
    throw new Error('Only batch script files are supported for .NET Web Application');
  }

  if (!this.solutionPath && !this.noSolution) {
    throw new Error('Missing solution file path (--solutionPath), to explicitly not require a solution use the flag --no-solution');
  }

  log.info('Generating deployment script for .NET Web Application');

  var msbuildArguments = '"%DEPLOYMENT_SOURCE%\\' + this.projectPath + '" /nologo /verbosity:m /t:Build /t:pipelinePreDeployCopyAllFilesToOneFolder /p:_PackageTempDir="%DEPLOYMENT_TEMP%";AutoParameterizationWebConfigConnectionStrings=false;Configuration=Release';

  if (this.solutionPath != null) {
    var solutionDir = path.dirname(this.solutionPath);
    msbuildArguments += ' /p:SolutionDir="%DEPLOYMENT_SOURCE%\\' + solutionDir + '\\\\\"';
  }

    msbuildArguments += ' %SCM_BUILD_ARGS%';

  this.generateDotNetDeploymentScript('deploy.batch.aspnet.wap.template', msbuildArguments, _);
}

ScriptGenerator.prototype.generateWebSiteDeploymentScript = function (_) {
  if (this.solutionPath) {
    // Solution based website (.NET)
    log.info('Generating deployment script for .NET Web Site');

    if (this.scriptType != ScriptType.batch) {
      throw new Error('Only batch script files are supported for .NET Web Site');
    }

    var msbuildArguments = '"%DEPLOYMENT_SOURCE%\\' + fixPathSeperatorToWindows(this.solutionPath) + '" /verbosity:m /nologo %SCM_BUILD_ARGS%';
    this.generateDotNetDeploymentScript('deploy.batch.aspnet.website.template', msbuildArguments, _);
  } else {
    // Basic website
    log.info('Generating deployment script for Web Site');

    var packageJsonFilePath = path.join(this.absoluteSitePath, 'package.json');
    if (fs.existsSync(packageJsonFilePath)) {
      // On package.json, use node.template which will install npm packages
      this.generateBasicDeploymentScript('node.template', _);
    } else {
      // Otherwise it's a simple copy to deploy
      this.generateBasicDeploymentScript('basic.template', _);
    }
  }
}

ScriptGenerator.prototype.generateBasicDeploymentScript = function (templateFileName, _) {
  argNotNull(templateFileName, 'templateFileName');

  var lowerCaseScriptType = this.scriptType.toLowerCase();
  var fixedSitePath = this.scriptType === ScriptType.batch ? fixPathSeperatorToWindows(this.sitePath) : fixPathSeperatorToUnix(this.sitePath);
  var templateContent =
      getTemplatesContent([
          'deploy.' + lowerCaseScriptType + '.prefix.template',
          'deploy.' + lowerCaseScriptType + '.' + templateFileName,
          'deploy.' + lowerCaseScriptType + '.postfix.template'])
      .replace(/{SitePath}/g, fixedSitePath);

  this.writeDeploymentFiles(templateContent, _);
}

ScriptGenerator.prototype.generateDotNetDeploymentScript = function (templateFileName, msbuildArguments, _) {
  argNotNull(templateFileName, 'templateFileName');

  var templateContent =
        getTemplatesContent([
            'deploy.batch.prefix.template',
            'deploy.batch.aspnet.template',
            templateFileName,
            'deploy.batch.postfix.template'])
        .replace(/{MSBuildArguments}/g, msbuildArguments)
        .replace(/{SitePath}/g, fixPathSeperatorToWindows(this.sitePath));

  this.writeDeploymentFiles(templateContent, _);
}

function getTemplatesContent(fileNames) {
  var content = '';

  for (var i in fileNames) {
    content += getTemplateContent(fileNames[i]);
  }

  return content;
}

function fixPathSeperatorToWindows(pathStr) {
  return pathStr.replace(/\//g, '\\');
}

function fixPathSeperatorToUnix(pathStr) {
  return pathStr.replace(/\\/g, '/');
}

ScriptGenerator.prototype.writeDeploymentFiles = function (templateContent, _) {
  argNotNull(templateContent, 'templateContent');

  var deployScriptFileName;
  var deploymentCommand;
  if (this.scriptType == ScriptType.batch) {
    deployScriptFileName = 'deploy.cmd';
    deploymentCommand = deployScriptFileName;
  } else {
    deployScriptFileName = 'deploy.sh';
    deploymentCommand = 'bash ' + deployScriptFileName;
  }

  var deployScriptPath = path.join(this.repositoryRoot, deployScriptFileName);
  var deploymentFilePath = path.join(this.repositoryRoot, '.deployment');

  // Write the custom deployment script
  writeContentToFile(deployScriptPath, templateContent, _);

  if (!this.noDotDeployment) {
    // Write the .deployment file
    writeContentToFile(deploymentFilePath, '[config]\ncommand = ' + deploymentCommand, _);
  }

  log.info('Generated deployment script files');
}

function getTemplateContent(templateFileName) {
  return fs.readFileSync(getTemplatePath(templateFileName), 'utf8');
}

function getTemplatePath(fileName) {
  return path.join(templatesDir, fileName);
}

function writeContentToFile(path, content, _) {
  // TODO: Add check whether file exist
  if (fs.existsSync(path)) {
    if (!confirm('The file: "' + path + '" already exists\nAre you sure you want to overwrite it (y/n): ', _)) {
      // Do not overwrite the file
      return;
    }
  }

  fs.writeFile(path, content, _);
}

function argNotNull(arg, argName) {
  if (arg === null || arg === undefined) {
    throw new Error('The argument "' + argName + '" is null');
  }
}

exports.ScriptGenerator = ScriptGenerator;
<|endoftext|>


<commit_before>define( [ "ember" ],function( Ember ) {

	return Ember.Mixin.create({
		offset: 0,
		limit: 12,
		maxAutoFetches: 3,

		beforeModel: function() {
			this._super.apply( this, arguments );

			this.set( "offset", 0 );
		},

		setupController: function( controller ) {
			this._super.apply( this, arguments );

			controller.set( "isFetching", false );
			controller.set( "hasFetchedAll", false );
		},

		fetchContent: function() {
			return this.model();
		},

		actions: {
			"willFetchContent": function( force ) {
				var controller = this.get( "controller" );
				if ( !controller.get( "isFetching" ) && !controller.get( "hasFetchedAll" ) ) {
					// don't fetch more than 3 times automatically
					var numFetches = this.get( "offset" ) / this.get( "limit" );
					if ( !force && this.get( "maxAutoFetches" ) <= numFetches ) {
						return;
					}

					controller.toggleProperty( "isFetching" );
					this.incrementProperty( "offset", this.get( "limit" ) );

					// fetch content and append to ArrayController
					this.fetchContent().then(function( content ) {
						if ( !content || !content.length ) {
							controller.set( "hasFetchedAll", true );
						} else {
							controller.pushObjects( content );
						}
						controller.toggleProperty( "isFetching" );
					}.bind( this ) );
				}
			}
		}
	});

});
<commit_msg>Fixed infinitescroll button showing up when there's nothing more to fetch<commit_after>define( [ "ember" ],function( Ember ) {

	return Ember.Mixin.create({
		offset: 0,
		limit: 12,
		maxAutoFetches: 3,

		beforeModel: function() {
			this._super.apply( this, arguments );

			this.set( "offset", 0 );
		},

		setupController: function( controller, model ) {
			var	num	= Ember.get( model, "length" ),
				max	= Ember.get( this, "limit" );

			this._super.apply( this, arguments );

			controller.set( "isFetching", false );
			controller.set( "hasFetchedAll", num < max );
		},

		fetchContent: function() {
			return this.model();
		},

		actions: {
			"willFetchContent": function( force ) {
				var controller = this.get( "controller" );
				if ( !controller.get( "isFetching" ) && !controller.get( "hasFetchedAll" ) ) {
					// don't fetch more than 3 times automatically
					var numFetches = this.get( "offset" ) / this.get( "limit" );
					if ( !force && this.get( "maxAutoFetches" ) <= numFetches ) {
						return;
					}

					controller.toggleProperty( "isFetching" );
					this.incrementProperty( "offset", this.get( "limit" ) );

					// fetch content and append to ArrayController
					this.fetchContent().then(function( content ) {
						if ( !content || !content.length ) {
							controller.set( "hasFetchedAll", true );
						} else {
							controller.pushObjects( content );
						}
						controller.toggleProperty( "isFetching" );
					}.bind( this ) );
				}
			}
		}
	});

});
<|endoftext|>


<commit_before>import { includePaths, excludePaths } from '../config/utils';

export default options => ({
  test: /\.(mjs|jsx?)$/,
  use: [
    {
      loader: 'babel-loader',
      options,
    },
  ],
  include: includePaths,
  exclude: excludePaths,
});

export const nodeModulesBabelLoader = {
  test: /\.js$/,
  include: /\/node_modules\/safe-eval\//,
  use: [
    {
      loader: 'babel-loader',
      options: {
        cacheDirectory: true,
        babelrc: false,
        presets: [
          [
            'env',
            {
              modules: 'commonjs',
            },
          ],
        ],
      },
    },
  ],
};
<commit_msg>Revert "Make nodeModulesBabelLoader compatible with Babel 6"<commit_after>import { includePaths, excludePaths } from '../config/utils';

export default options => ({
  test: /\.(mjs|jsx?)$/,
  use: [
    {
      loader: 'babel-loader',
      options,
    },
  ],
  include: includePaths,
  exclude: excludePaths,
});

export const nodeModulesBabelLoader = {
  test: /\.js$/,
  include: /\/node_modules\/safe-eval\//,
  use: [
    {
      loader: 'babel-loader',
      options: {
        cacheDirectory: true,
        babelrc: false,
        presets: [
          [
            require.resolve('@babel/preset-env'),
            {
              useBuiltIns: 'usage',
              modules: 'commonjs',
            },
          ],
        ],
      },
    },
  ],
};
<|endoftext|>