diff --git a/bin/browser-sync.js b/bin/browser-sync.js index dae7627a3..5c9443e5d 100755 --- a/bin/browser-sync.js +++ b/bin/browser-sync.js @@ -6,9 +6,7 @@ var fs = require("fs"); var path = require("path"); var compile = require("eazy-logger").compile; var utils = require("../lib/utils"); -var flags = require("../lib/cli/opts"); -var flagKeys = Object.keys(flags); - +var logger = require("../lib/logger").logger; var cmdWhitelist = ["start", "init", "reload"]; var cli = meow({ @@ -29,20 +27,23 @@ if (!module.parent) { * @returns {String} */ function getHelpText(filepath) { - return compile( - fs.readFileSync( - filepath, - "utf8" - ).replace( - "%flags%", - listFlags( - flags, - longest( - flagKeys - ).length - ) - ) - ); + + /** + * Help text template + */ + var template = fs.readFileSync(filepath, "utf8"); + + cmdWhitelist.forEach(function (command) { + + var flags = require("../lib/cli/opts." + command + ".json"); + + template = template.replace( + ["%", command, "flags%"].join(""), + listFlags(flags) + ); + }); + + return compile(template); } /** @@ -54,7 +55,6 @@ function handleCli (opts) { opts.cb = opts.cb || utils.defaultCallback; var input = opts.cli.input; - var flags = opts.cli.flags; if (!opts.whitelist) { opts.whitelist = cmdWhitelist; @@ -64,24 +64,28 @@ function handleCli (opts) { return console.log(opts.cli.help); } - if (input[0] === "start") { - require("../lib/cli/command.start")(opts); - } - - if (input[0] === "init") { - require("../lib/cli/command.init")(opts); + if (!require("../lib/cli/cli-utils").verifyOpts(input[0], opts.cli.flags)) { + logger.info("For help, run: {cyan:browser-sync --help}"); + return opts.cb(new Error("Unknown flag given. Please refer to the documentation for help.")); } + return require("../lib/cli/command." + input[0])(opts); } /** * @param {Object} flags - * @param {Number} longest - * @returns {String} */ -function listFlags (flags, longest) { +function listFlags (flags) { + + var flagKeys = Object.keys(flags); + var longest = getLongest(Object.keys(flags)); + + if (!longest || !longest.length) { + return; + } + return flagKeys.reduce(function (all, item) { - return all + " {bold:--" + item + "}" + getPadding(item.length, longest + 8) + flags[item] + "\n"; + return all + " {bold:--" + item + "}" + getPadding(item.length, longest.length + 8) + flags[item] + "\n"; }, ""); } @@ -98,7 +102,7 @@ function getPadding (len, max) { * @param {Array} arr * @returns {String} */ -function longest (arr) { +function getLongest (arr) { return arr.sort(function (a, b) { return b.length - a.length; })[0]; } diff --git a/lib/async.js b/lib/async.js index c6a971288..65261e68c 100644 --- a/lib/async.js +++ b/lib/async.js @@ -234,16 +234,12 @@ module.exports = { */ addHttpProtocol: function (bs, done) { - if (!bs.options.get("httpProtocol")) { - return done(null); - } - /** * Add a middleware to listen to http * requests in the BrowserSync http protocol namespace */ bs.addMiddleware( - bs.options.getIn(["httpProtocol", "path"]), + require("./config").httpProtocol.path, require("./http-protocol").middleware(bs), {override: true} ); diff --git a/lib/cli/cli-utils.js b/lib/cli/cli-utils.js index da06e8442..eecf6fe69 100644 --- a/lib/cli/cli-utils.js +++ b/lib/cli/cli-utils.js @@ -2,11 +2,13 @@ var utils = exports; var logger = require("../logger").logger; -var flags = require("./opts.json"); -var flagKeys = Object.keys(flags); var _ = require("lodash"); -utils.verifyOpts = function (flagWhitelist, cliFlags) { +utils.verifyOpts = function (optskey, cliFlags) { + + var flags = require("./opts." + optskey + ".json"); + var flagKeys = Object.keys(flags); + var flagWhitelist = flagKeys.map(dropPrefix).map(_.camelCase); return Object.keys(cliFlags).every(function (key) { @@ -19,3 +21,11 @@ utils.verifyOpts = function (flagWhitelist, cliFlags) { return false; }); }; + +/** + * @param {String} item + * @returns {String} + */ +function dropPrefix (item) { + return item.replace("no-", ""); +} diff --git a/lib/cli/command.reload.js b/lib/cli/command.reload.js new file mode 100644 index 000000000..bfa49f95e --- /dev/null +++ b/lib/cli/command.reload.js @@ -0,0 +1,29 @@ +"use strict"; + +var error = "Could not contact BrowserSync server."; + +/** + * $ browser-sync reload + * + * This commands starts the BrowserSync servers + * & Optionally UI. + * + * @param opts + * @returns {Function} + */ +module.exports = function (opts) { + + var flags = opts.cli.flags; + var proto = require("../http-protocol"); + + var url = proto.getUrl({method: "reload", args: flags.files}, "http://localhost:" + (flags.port || 3000)); + + require("http").get(url, function (res) { + if (res.statusCode !== 200) { + require("logger").logger.error(error); + return opts.cb(new Error(error)); + } else { + opts.cb(null, res); + } + }); +}; diff --git a/lib/cli/command.start.js b/lib/cli/command.start.js index 460ac85b8..ee37224d4 100644 --- a/lib/cli/command.start.js +++ b/lib/cli/command.start.js @@ -1,11 +1,6 @@ "use strict"; -var logger = require("../logger").logger; -var info = require("./cli-info"); -var flags = require("./opts.json"); -var _ = require("lodash"); -var flagKeys = Object.keys(flags); -var flagWhitelist = flagKeys.map(dropPrefix).map(_.camelCase); +var info = require("./cli-info"); /** * $ browser-sync start @@ -20,20 +15,7 @@ module.exports = function (opts) { var flags = opts.cli.flags; - if (!require("./cli-utils").verifyOpts(flagWhitelist, flags)) { - logger.info("For help, run: {cyan:browser-sync --help}"); - return opts.cb(new Error("Unknown flag given. Please refer to the documentation for help.")); - } - return require("../../") .create("cli") .init(flags.config ? info.getConfigFile(flags.config) : flags, opts.cb); }; - -/** - * @param {String} item - * @returns {String} - */ -function dropPrefix (item) { - return item.replace("no-", ""); -} diff --git a/lib/cli/help.txt b/lib/cli/help.txt index b356037c6..6e12bc25e 100644 --- a/lib/cli/help.txt +++ b/lib/cli/help.txt @@ -8,11 +8,17 @@ {bold:init} Creates a default config file {bold:start} Start Browser Sync + {bold:reload} Send a reload event over HTTP protocol -{bold:Options:} +{bold:`start` Options:} {gray:--------} -%flags% +%startflags% + +{bold:`reload` Options:} +{gray:--------} + +%reloadflags% {cyan:Server Example:} {gray:---------------} diff --git a/lib/cli/opts.init.json b/lib/cli/opts.init.json new file mode 100644 index 000000000..9e26dfeeb --- /dev/null +++ b/lib/cli/opts.init.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/lib/cli/opts.reload.json b/lib/cli/opts.reload.json new file mode 100644 index 000000000..e9411cc45 --- /dev/null +++ b/lib/cli/opts.reload.json @@ -0,0 +1,4 @@ +{ + "files": "File paths to reload", + "port": "Target a running instance by port number" +} diff --git a/lib/cli/opts.json b/lib/cli/opts.start.json similarity index 100% rename from lib/cli/opts.json rename to lib/cli/opts.start.json diff --git a/lib/config.js b/lib/config.js index efc125454..5fb59c7f1 100644 --- a/lib/config.js +++ b/lib/config.js @@ -17,6 +17,9 @@ module.exports = { configFile: "/default-config.js", userFile: "/bs-config.js", template: "/cli-template.js", + httpProtocol: { + path: "/__browser_sync__" + }, client: { shims: "/client/client-shims.js" }, diff --git a/lib/default-config.js b/lib/default-config.js index bf6cd1709..0ad95379a 100644 --- a/lib/default-config.js +++ b/lib/default-config.js @@ -339,16 +339,6 @@ module.exports = { } }, - /** - * @property httpProtocol - * @param {String} [path="/__browser_sync__"] - * @since 2.6.0 - * @type Object - */ - httpProtocol: { - path: "/__browser_sync__" - }, - /** * A map of file-extensions -> dom element. * Useful if you're serving files with unusual file extensions diff --git a/lib/http-protocol.js b/lib/http-protocol.js index b3bd27f25..676b8b932 100644 --- a/lib/http-protocol.js +++ b/lib/http-protocol.js @@ -12,13 +12,13 @@ var proto = exports; * Eg. http://localhost:3000/__browser_sync__?method=reload&args=core.css&args=core.min * * @param args - * @param bs + * @param url * @returns {string} */ -proto.getUrl = function (args, bs) { +proto.getUrl = function (args, url) { return [ - bs.options.getIn(["urls", "local"]), - bs.options.getIn(["httpProtocol", "path"]), + url, + require("./config").httpProtocol.path, "?", queryString.stringify(args) ].join(""); diff --git a/lib/public/reload.js b/lib/public/reload.js index 8fbd9e544..349a833a9 100644 --- a/lib/public/reload.js +++ b/lib/public/reload.js @@ -28,7 +28,7 @@ module.exports = function (emitter) { return function (arg) { - if (typeof arg === "string") { + if (typeof arg === "string" && arg !== "undefined") { return emitReload(arg, true); } diff --git a/test/specs/commands/reload.js b/test/specs/commands/reload.js index 51668fb83..9b5ec1553 100644 --- a/test/specs/commands/reload.js +++ b/test/specs/commands/reload.js @@ -1,19 +1,16 @@ "use strict"; var path = require("path"); -//var utils = require("../../../lib/utils"); -//var assert = require("chai").assert; var browserSync = require(path.resolve("./")); var pkg = require(path.resolve("package.json")); var sinon = require("sinon"); var cli = require(path.resolve(pkg.bin)); -describe.skip("E2E CLI `reload` with no files arg", function () { - it("should make a http request to the protocol", function (done) { +describe("E2E CLI `reload` with no files arg", function () { + it("should make a http request to the protocol with no files arg", function (done) { browserSync.reset(); - browserSync .create() .init({server: "test/fixtures", open: false}, function (err, bs) { @@ -28,7 +25,35 @@ describe.skip("E2E CLI `reload` with no files arg", function () { } }, cb: function () { - sinon.assert.called(spy); + sinon.assert.calledWithExactly(spy, "browser:reload"); + bs.cleanup(); + done(); + } + }); + }); + }); + + it("should make a http request with files arg", function (done) { + + browserSync.reset(); + + browserSync + .create() + .init({server: "test/fixtures", open: false}, function (err, bs) { + + var spy = sinon.spy(bs.events, "emit"); + + cli({ + cli: { + input: ["reload"], + flags: { + port: bs.options.get("port"), + files: "core.css" + } + }, + cb: function () { + sinon.assert.calledWithExactly(spy, "file:changed", {path: "core.css", log: true, namespace: "core"}); + bs.cleanup(); done(); } }); diff --git a/test/specs/http-protocol/http.reload.js b/test/specs/http-protocol/http.reload.js index 0173a158c..fc7b7274d 100644 --- a/test/specs/http-protocol/http.reload.js +++ b/test/specs/http-protocol/http.reload.js @@ -36,7 +36,7 @@ describe("HTTP protocol", function () { it("responds to reload event with no args", function (done) { - var url = proto.getUrl({method: "reload"}, bs); + var url = proto.getUrl({method: "reload"}, bs.options.getIn(["urls", "local"])); request(url, function (e, r, body) { sinon.assert.calledWith(spy, "browser:reload"); @@ -47,7 +47,7 @@ describe("HTTP protocol", function () { }); it("responds to reload event with multi file paths", function (done) { - var url = proto.getUrl({method: "reload", args: ["core.min.css", "core.css"]}, bs); + var url = proto.getUrl({method: "reload", args: ["core.min.css", "core.css"]}, bs.options.getIn(["urls", "local"])); request(url, function (e, r, body) { sinon.assert.calledWith(spy, "file:changed"); @@ -59,7 +59,7 @@ describe("HTTP protocol", function () { }); it("responds to reload event with single file path", function (done) { - var url = proto.getUrl({method: "reload", args: "somefile.php"}, bs); + var url = proto.getUrl({method: "reload", args: "somefile.php"}, bs.options.getIn(["urls", "local"])); request(url, function (e, r, body) { sinon.assert.calledWith(spy, "file:changed");