diff --git a/.eslintrc b/.eslintrc index 331ecbe0..8451f905 100644 --- a/.eslintrc +++ b/.eslintrc @@ -2,7 +2,7 @@ "extends": "gulp", "rules": { "max-len": [1, 130], - "max-statements": [1, 40], + "max-statements": [1, 60], "no-console": "off" } } diff --git a/.github/workflows/dev.yml b/.github/workflows/dev.yml index 90a12261..da91898f 100644 --- a/.github/workflows/dev.yml +++ b/.github/workflows/dev.yml @@ -56,6 +56,12 @@ jobs: # Run test without coverage because a behavior about esm is different with nyc or not run: npm test + - name: Run tests with coloring + run: npx mocha test/lib/theme.js + env: + FORCE_COLOR: 2 + CI: "" + coveralls: needs: test name: Finish up diff --git a/.gitignore b/.gitignore index 3b569a93..9ad73290 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ *.log node_modules !test/fixtures/errors/bad-gulp-version/node_modules/ +!test/fixtures/config/theming/error/badGulpVersion/node_modules/ build *.node components diff --git a/README.md b/README.md index bde183fd..915f0575 100644 --- a/README.md +++ b/README.md @@ -107,7 +107,6 @@ Supported configurations properties: | Property | Description | |--------------------|-------------| -| description | Top-level description of the project/gulpfile (Replaces "Tasks for ~/path/of/gulpfile.js") | | flags.continue | Continue execution of tasks upon failure by default. | | flags.compactTasks | Reduce the output of task dependency tree by default. | | flags.tasksDepth | Set default depth of task dependency tree. | @@ -116,6 +115,8 @@ Supported configurations properties: | flags.series | Run tasks given on the CLI in series (the default is parallel) | | flags.preload | An array of modules to preload before running the gulpfile. Any relative paths will be resolved against the `--cwd` directory (if you don't want that behavior, use absolute paths) | | flags.nodeFlags | An array of flags used to forcibly respawn the process upon startup. For example, if you always want your gulpfiles to run in node's harmony mode, you can set `--harmony` here | +| log.msgs.* | Configure log messages. | +| log.theme.* | Configure log theme. | ## Flags diff --git a/index.js b/index.js index 935f8928..ebf3eb01 100644 --- a/index.js +++ b/index.js @@ -3,22 +3,23 @@ var fs = require('fs'); var path = require('path'); var log = require('gulplog'); - var Liftoff = require('liftoff'); var interpret = require('interpret'); var v8flags = require('v8flags'); var findRange = require('semver-greatest-satisfied-range'); -var chalk = require('chalk'); + var exit = require('./lib/shared/exit'); var tildify = require('./lib/shared/tildify'); var makeTitle = require('./lib/shared/make-title'); var parser = require('./lib/shared/options/parser'); +var makeHelp = require('./lib/shared/options/make-help'); var completion = require('./lib/shared/completion'); var cliVersion = require('./package.json').version; var toConsole = require('./lib/shared/log/to-console'); +var msgs = require('./lib/shared/log/messages'); var mergeProjectAndUserHomeConfigs = require('./lib/shared/config/merge-configs'); -var overrideEnvFlagsByConfigAndCliOpts = require('./lib/shared/config/env-flags'); +var overrideEnvByConfigAndCliOpts = require('./lib/shared/config/env-config'); // Get supported ranges var ranges = fs.readdirSync(path.join(__dirname, '/lib/versioned/')); @@ -52,25 +53,24 @@ var cli = new Liftoff({ }, }); -var opts = parser.argv; +var opts = {}; +var optsErr; +try { + opts = parser.argv; +} catch (e) { + optsErr = e; +} cli.on('preload:before', function(name) { - log.info('Preloading external module:', chalk.magenta(name)); + log.info(msgs.info.preloadBefore, name); }); cli.on('preload:success', function(name) { - log.info('Preloaded external module:', chalk.magenta(name)); + log.info(msgs.info.preloadSuccess, name); }); cli.on('preload:failure', function(name, error) { - log.warn( - chalk.yellow('Failed to preload external module:'), - chalk.magenta(name) - ); - /* istanbul ignore else */ - if (error) { - log.warn(chalk.yellow(error.toString())); - } + log.warn(msgs.warn.preloadFailure, name, Boolean(error), error.toString()); }); cli.on('loader:success', function(name) { @@ -79,26 +79,16 @@ cli.on('loader:success', function(name) { // However, we don't want to show the mjs-stub loader in the logs /* istanbul ignore else */ if (path.basename(name, '.js') !== 'mjs-stub') { - log.info('Loaded external module:', chalk.magenta(name)); + log.info(msgs.info.loaderSuccess, name); } }); cli.on('loader:failure', function(name, error) { - log.warn( - chalk.yellow('Failed to load external module:'), - chalk.magenta(name) - ); - /* istanbul ignore else */ - if (error) { - log.warn(chalk.yellow(error.toString())); - } + log.warn(msgs.warn.loaderFailure, name, Boolean(error), error.toString()); }); cli.on('respawn', function(flags, child) { - var nodeFlags = chalk.magenta(flags.join(', ')); - var pid = chalk.magenta(child.pid); - log.info('Node flags detected:', nodeFlags); - log.info('Respawned to PID:', pid); + log.info(msgs.info.respawn, flags.join(', '), child.pid); }); function run() { @@ -114,7 +104,7 @@ module.exports = run; function onPrepare(env) { var cfg = mergeProjectAndUserHomeConfigs(env); - env = overrideEnvFlagsByConfigAndCliOpts(env, cfg, opts); + env = overrideEnvByConfigAndCliOpts(env, cfg, opts); // Set up event listeners for logging again after configuring. toConsole(log, env.config.flags); @@ -132,8 +122,13 @@ function onExecute(env) { process.env.UNDERTAKER_SETTLE = 'true'; } + if (optsErr) { + log.error(msgs.error.failToParseCliOpts, optsErr.message); + makeHelp(parser).showHelp(console.error); + exit(1); + } if (env.config.flags.help) { - parser.showHelp(console.log); + makeHelp(parser).showHelp(console.log); exit(0); } @@ -145,36 +140,23 @@ function onExecute(env) { } if (!env.modulePath) { - /* istanbul ignore next */ var missingNodeModules = fs.existsSync(path.join(env.cwd, 'package.json')) && !fs.existsSync(path.join(env.cwd, 'node_modules')); - /* istanbul ignore next */ - var missingGulpMessage = - missingNodeModules - ? 'Local modules not found in' - : 'Local gulp not found in'; - log.error( - chalk.red(missingGulpMessage), - chalk.magenta(tildify(env.cwd)) - ); var hasYarn = fs.existsSync(path.join(env.cwd, 'yarn.lock')); - /* istanbul ignore next */ - var installCommand = - missingNodeModules - ? hasYarn - ? 'yarn install' - : 'npm install' - : hasYarn - ? 'yarn add gulp' - : 'npm install gulp'; - log.error(chalk.red('Try running: ' + installCommand)); + var hasNpm = !hasYarn; + + if (missingNodeModules) { + log.error(msgs.error.nodeModulesNotFound, tildify(env.cwd), hasYarn, hasNpm); + } else { + log.error(msgs.error.gulpNotFound, tildify(env.cwd), hasYarn, hasNpm); + } exit(1); } if (!env.configPath) { - log.error(chalk.red('No gulpfile found')); + log.error(msgs.error.gulpfileNotFound); exit(1); } @@ -182,19 +164,14 @@ function onExecute(env) { // we let them chdir as needed if (process.cwd() !== env.cwd) { process.chdir(env.cwd); - log.info( - 'Working directory changed to', - chalk.magenta(tildify(env.cwd)) - ); + log.info(msgs.info.cwdChanged, tildify(env.cwd)); } // Find the correct CLI version to run var range = findRange(env.modulePackage.version, ranges); if (!range) { - log.error( - chalk.red('Unsupported gulp version', env.modulePackage.version) - ); + log.error(msgs.error.badGulpVersion, env.modulePackage.version); exit(1); } diff --git a/lib/shared/completion.js b/lib/shared/completion.js index 3a47023d..1f1a7cc3 100644 --- a/lib/shared/completion.js +++ b/lib/shared/completion.js @@ -2,21 +2,21 @@ var fs = require('fs'); var path = require('path'); +var format = require('theming-log').format; + +var theme = require('./log/theme'); +var msgs = require('./log/messages'); module.exports = function(name) { if (typeof name !== 'string') { - throw new Error('Missing completion type'); + throw new Error(format(theme, msgs.error.noCompletionType)); } var file = path.join(__dirname, '../../completion', name); try { console.log(fs.readFileSync(file, 'utf8')); process.exit(0); } catch (err) { - console.log( - 'echo "gulp autocompletion rules for', - '\'' + name + '\'', - 'not found"' - ); + console.log(format(theme, msgs.error.unknownCompletionType, name)); process.exit(5); } }; diff --git a/lib/shared/config/env-flags.js b/lib/shared/config/env-config.js similarity index 73% rename from lib/shared/config/env-flags.js rename to lib/shared/config/env-config.js index 59b4d4be..18265465 100644 --- a/lib/shared/config/env-flags.js +++ b/lib/shared/config/env-config.js @@ -5,6 +5,9 @@ var copyProps = require('copy-props'); var mergeCliOpts = require('./cli-flags'); +var theme = require('../log/theme'); +var msgs = require('../log/messages'); + var toEnvFromConfig = { configPath: 'flags.gulpfile', configBase: 'flags.gulpfile', @@ -12,7 +15,7 @@ var toEnvFromConfig = { nodeFlags: 'flags.nodeFlags', }; -function overrideEnvFlags(env, config, cliOpts) { +function overrideEnvConfig(env, config, cliOpts) { cliOpts = mergeCliOpts(cliOpts, config); // This must reverse because `flags.gulpfile` determines 2 different properties @@ -21,9 +24,18 @@ function overrideEnvFlags(env, config, cliOpts) { env.config = { flags: cliOpts, + log: { + theme: theme, + msgs: msgs, + }, }; - if (config.description) { - env.config.description = config.description; + if (config.log) { + if (config.log.theme) { + copyProps(config.log.theme, env.config.log.theme); + } + if (config.log.msgs) { + copyProps(config.log.msgs, env.config.log.msgs); + } } return env @@ -53,4 +65,4 @@ function overrideEnvFlags(env, config, cliOpts) { } } -module.exports = overrideEnvFlags; +module.exports = overrideEnvConfig; diff --git a/lib/shared/config/merge-configs.js b/lib/shared/config/merge-configs.js index 8202f182..e3c17a81 100644 --- a/lib/shared/config/merge-configs.js +++ b/lib/shared/config/merge-configs.js @@ -5,6 +5,7 @@ var path = require('path'); function mergeConfigs(env) { var cfg = {}; + /* istanbul ignore if */ if (env.configFiles.userHome) { copyConfig(env.config.userHome, cfg, env.configFiles.userHome); } diff --git a/lib/shared/log/messages.js b/lib/shared/log/messages.js new file mode 100644 index 00000000..b945b182 --- /dev/null +++ b/lib/shared/log/messages.js @@ -0,0 +1,174 @@ +'use strict'; + +/* eslint max-len: 0 */ + +module.exports = { + help: { + usage: + '\n{TITLE: Usage:} gulp {OPTION: [options]} {TASK: tasks}', + + flags: { + help: + '{HELP.DESC: Show this help.}', + + version: + '{HELP.DESC: Print the global and local gulp versions.}', + + preload: + '{HELP.DESC: Will preload a module before running the gulpfile. ' + + 'This is useful for transpilers but also has other applications.}', + + gulpfile: + '{HELP.DESC: Manually set path of gulpfile. Useful if you have ' + + 'multiple gulpfiles. This will set the CWD to the gulpfile ' + + 'directory as well.}', + + cwd: + '{HELP.DESC: Manually set the CWD. The search for the gulpfile, ' + + 'as well as the relativity of all requires will be from here.}', + + tasks: + '{HELP.DESC: Print the task dependency tree for the loaded ' + + 'gulpfile.}', + + 'tasks-simple': + '{HELP.DESC: Print a plaintext list of tasks for the loaded ' + + 'gulpfile.}', + + 'tasks-json': + '{HELP.DESC: Print the task dependency tree, in JSON format, ' + + 'for the loaded gulpfile.}', + + 'tasks-depth': + '{HELP.DESC: Specify the depth of the task dependency tree.}', + + 'compact-tasks': + '{HELP.DESC: Reduce the output of task dependency tree by ' + + 'printing only top tasks and their child tasks.}', + + 'sort-tasks': + '{HELP.DESC: Will sort top tasks of task dependency tree.}', + + color: + '{HELP.DESC: Will force gulp and gulp plugins to display ' + + 'colors, even when no color support is detected.}', + + 'no-color': + '{HELP.DESC: Will force gulp and gulp plugins to not display ' + + 'colors, even when color support is detected.}', + + silent: + '{HELP.DESC: Suppress all gulp logging.}', + + continue: + '{HELP.DESC: Continue execution of tasks upon failure.}', + + series: + '{HELP.DESC: Run tasks given on the CLI in series (the default ' + + 'is parallel).}', + + 'log-level': + '{HELP.DESC: Set the loglevel. -L for least verbose and -LLLL ' + + 'for most verbose. -LLL is default.}', + }, + }, + tasks: { + description: + '{DESC: Tasks for} {PATH: {1:gulpfile path}}', + + topTask: + '{TASKS.BRANCH: {1:branch line}}{TASKS.NAME: {2:task name}}{IF:{3:has desc}?{4:space}{TASKS.DESC: {5:task description}}}', + + option: + '{TASKS.BRANCH: {1:branch line}}{TASKS.OPTION: {2:option name}}{IF:{3:has desc}?{4:space}…{TASKS.DESC: {5:option description}}', + + childTask: + '{TASKS.BRANCH: {1:branch line}{TASKS.CHILD: {2:task name}}', + }, + + tasksJson: { + description: + 'Tasks for {1:gulpfile path}', + }, + + info: { + preloadBefore: + '{TIMESTAMP}{DESC: Preloading external module:} {MODULE: {1:module name}}', + + preloadSuccess: + '{TIMESTAMP}{DESC: Preloaded external module:} {MODULE: {1:module name}}', + + loaderSuccess: + '{TIMESTAMP}{DESC: Loaded external module:} {MODULE: {1:module name}}', + + respawn: + '{TIMESTAMP}{DESC: Node flags detected:} {OPTION: {1:node flags}}\n' + + '{TIMESTAMP}{DESC: Respawned to PID: {PID: {2:pid}}', + + cwdChanged: + '{TIMESTAMP}{DESC: Working directory changed to} {PATH: {1:cwd}}', + + usingGulpfile: + '{TIMESTAMP}{DESC: Using gulpfile} {PATH: {1:gulpfile path}}', + + taskStart: + '{TIMESTAMP}{DESC: Starting \'}{TASK: {1:task name}}{DESC: \'...}', + + taskStop: + '{TIMESTAMP}{DESC: Finished \'}{TASK: {1:task name}}{DESC: \' after} ' + + '{DURATION: {2:duration}}', + }, + + warn: { + preloadFailure: + '{TIMESTAMP}{WARN: Failed to preload external module:} {MODULE: {1: module name}}\n' + + '{IF:{2:exists error}?{TIMESTAMP}{WARN: {3:error message}} ', + + loaderFailure: + '{TIMESTAMP}{WARN: Failed to load external module:} {MODULE: {1: module name}}\n' + + '{IF:{2:exists error}?{TIMESTAMP}{WARN: {3:error message}} ', + + taskNotComplete: + '{TIMESTAMP}{WARN: The following tasks did not complete:} {TASK: {1}}\n' + + '{TIMESTAMP}{WARN: Did you forget to signal async completion? }', + }, + + error: { + failToParseCliOpts: + '{ERROR: {1:error message}}', + + gulpNotFound: + '{TIMESTAMP}{ERROR: Local gulp not found in} {PATH: {1}}\n' + + '{TIMESTAMP}{ERROR: Try running: {IF:{2:has yarn}?yarn add}{IF:{3:has npm}?npm install} gulp}', + + nodeModulesNotFound: + '{TIMESTAMP}{ERROR: Local modules not found in} {PATH: {1}}\n' + + '{TIMESTAMP}{ERROR: Try running: {IF:{2:has yarn}?yarn install}{IF:{3:has npm}?npm install}', + + gulpfileNotFound: + '{TIMESTAMP}{ERROR: No gulpfile found}', + + badGulpVersion: + '{TIMESTAMP}{ERROR: Unsupported gulp version {VERSION: {1}}}', + + taskError: + '{TIMESTAMP}{ERROR: \'{1:task}\' errored after} ' + + '{DURATION: {2:duration}}' + + '{IF:{3:has cause}?\n{TIMESTAMP}{ERROR: {4:cause}}}', + + taskNotFound: + '{TIMESTAMP}{ERROR: Task never defined: {1:target task}{IF:{2:has similar tasks}? - did you mean? {3:similar tasks}}\n' + + '{TIMESTAMP}{ERROR: To list available tasks, try running: gulp --tasks}', + + failToRun: + '{TIMESTAMP}{ERROR: {1:cause}}\n' + + '{TIMESTAMP}{ERROR: Please check the documentation for proper ' + + 'gulpfile formatting}', + + noCompletionType: + 'Missing completion type', + + unknownCompletionType: + 'echo "gulp autocompletion rules for \'{1:type}\' not found"', + }, +}; diff --git a/lib/shared/log/tasks.js b/lib/shared/log/tasks.js index 2d59fe35..2dc7a4d1 100644 --- a/lib/shared/log/tasks.js +++ b/lib/shared/log/tasks.js @@ -1,7 +1,10 @@ 'use strict'; var log = require('gulplog'); -var chalk = require('chalk'); +var stringWidth = require('string-width'); +var format = require('theming-log').format; +var theme = require('./theme'); +var msgs = require('./messages'); var isObject = require('../is-object'); function logTasks(tree, opts, getTask) { @@ -29,22 +32,23 @@ function logTasks(tree, opts, getTask) { function printTaskTree(tree, opts) { var lines = []; - lines.push({ label: tree.label }); var maxLabelWidth = 0; tree.nodes.forEach(function(node, idx, arr) { var isLast = idx === arr.length - 1; var w = createTreeLines(node, lines, opts, 1, '', isLast); - maxLabelWidth = Math.max(maxLabelWidth, w || 0); + maxLabelWidth = Math.max(maxLabelWidth, w); }); + log.info(msgs.tasks.description, tree.label); + lines.forEach(function(line) { - var s = line.label; if (line.desc) { - var spaces = ' '.repeat(maxLabelWidth - line.label.length) + ' '; - s += spaces + line.desc; + var spaces = ' '.repeat(maxLabelWidth - line.width) + ' '; + log.info(line.fmt, line.bars, line.name, true, spaces, line.desc); + } else { + log.info(line.fmt, line.bars, line.name); } - log.info(s); }); } @@ -81,21 +85,27 @@ function addTaskToLines(task, lines, isLast, isLeaf) { var line = {}; if (task.depth === 1) { - line.label = chalk.white(taskBars) + chalk.white(task.label); + line.fmt = msgs.tasks.topTask; + line.bars = taskBars; + line.name = task.label; } else { - line.label = chalk.white(taskBars) + chalk.cyan(task.label); + line.fmt = msgs.tasks.childTask; + line.bars = taskBars; + line.name = task.label; } + line.width = stringWidth(format(theme, line.fmt, line.bars, line.name)); + if (typeof task.desc === 'string' && task.desc) { - line.desc = chalk.white(task.desc); + line.desc = task.desc; } lines.push(line); - var maxLabelWidth = line.label.length - if (!isObject(task.flags)) { - return maxLabelWidth; + return line.width; } + var maxLabelWidth = line.width; + var flagBars = task.bars; if (isLast) { flagBars += ' '; @@ -114,13 +124,17 @@ function addTaskToLines(task, lines, isLast, isLeaf) { function addFlagsToLines(ent) { if (typeof ent[0] !== 'string' || !ent[0]) return; var line = {}; - lines.push(line); - line.label = chalk.white(flagBars) + chalk.magenta(ent[0]); + line.fmt = msgs.tasks.option; + line.bars = flagBars; + line.name = ent[0]; + line.width = stringWidth(format(theme, line.fmt, line.bars, line.name)); - maxLabelWidth = Math.max(maxLabelWidth, line.label.length); + maxLabelWidth = Math.max(maxLabelWidth, line.width); - if (typeof ent[1] !== 'string' || !ent[1]) return; - line.desc = chalk.white('…' + ent[1]); + if (typeof ent[1] == 'string' && ent[1]) { + line.desc = ent[1]; + } + lines.push(line); } return maxLabelWidth; diff --git a/lib/shared/log/theme.js b/lib/shared/log/theme.js new file mode 100644 index 00000000..4f8d002a --- /dev/null +++ b/lib/shared/log/theme.js @@ -0,0 +1,63 @@ +'use strict'; + +var chalk = require('chalk'); +var timestamp = require('./timestamp'); + +var theme = { + NOW: timestamp, + + HELP: { + DESC: '{gray: {1}}', + }, + + DESC: null, + PATH: '{magenta: {1}}', + PID: '{magenta: {1}}', + MODULE: '{magenta: {1}}', + VERSION: null, + TITLE: '{bold: {1}}', + TASK: '{cyan: {1}}', + OPTION: '{blue: {1}}', + DURATION: '{magenta: {1}}', + + TASKS: { + BRANCH: null, + NAME: '{TASK: {1}}', + OPTION: '{OPTION: {1}}', + DESC: '{DESC: {1}}', + CHILD: null, + }, + + INFO: null, + WARN: '{yellow: {1}}', + ERROR: '{red: {1}}', + + TIMESTAMP: '[{gray: {NOW: HH:mm:ss}}] ', + + IF: function(text) { + var idx = text.indexOf('?'); + var cond = text.substring(0, idx).trim(); + if (cond === '' || cond === 'false') { + return ''; + } + return text.slice(idx + 1); + }, +}; + +[ + 'reset', 'bold', 'dim', 'italic', 'underline', 'inverse', + 'hidden', 'strikethrough', 'visible', + + 'black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white', + 'blackBright', 'gray', 'grey', 'redBright', 'greenBright', 'yellowBright', + 'blueBright', 'magentaBright', 'cyanBright', 'whiteBright', + + 'bgBlack', 'bgRed', 'bgGreen', 'bgYellow', 'bgBlue', 'bgMagenta', 'bgCyan', + 'bgWhite', 'bgBlackBright', 'bgGray', 'bgGrey', 'bgRedBright', + 'bgGreenBright', 'bgYellowBright', 'bgBlueBright', 'bgMagentaBright', + 'bgCyanBright', 'bgWhiteBright', +].forEach(function(style) { + theme[style] = chalk[style]; +}); + +module.exports = theme; diff --git a/lib/shared/log/timestamp.js b/lib/shared/log/timestamp.js new file mode 100644 index 00000000..4e9dd9a6 --- /dev/null +++ b/lib/shared/log/timestamp.js @@ -0,0 +1,55 @@ +'use strict'; + +function timestamp(format) { + /* istanbul ignore if */ + if (typeof format !== 'string') { + return noop; + } + + var date = new Date(); + + var result = ''; + var arr = format.split(/(YYYY|MM|DD|HH|mm|ss|SSS)/); + for (var i = 0; i < arr.length; i++) { + var el = arr[i]; + switch (el) { + case 'YYYY': + result += align(date.getFullYear(), 4); + break; + case 'MM': + result += align(date.getMonth() + 1, 2); + break; + case 'DD': + result += align(date.getDate(), 2); + break; + case 'HH': + result += align(date.getHours(), 2); + break; + case 'mm': + result += align(date.getMinutes(), 2); + break; + case 'ss': + result += align(date.getSeconds(), 2); + break; + case 'SSS': + result += align(date.getMilliseconds(), 3); + break; + default: + result += el; + break; + } + } + + return result; +} + +/* istanbul ignore next */ +function noop() { + return ""; +} + +function align(v, n) { + return String(v).padStart(n, '0').slice(-n); +} + +module.exports = timestamp; diff --git a/lib/shared/log/to-console.js b/lib/shared/log/to-console.js index 43650af1..844343aa 100644 --- a/lib/shared/log/to-console.js +++ b/lib/shared/log/to-console.js @@ -1,6 +1,7 @@ 'use strict'; -var fancyLog = require('fancy-log'); +var themingLog = require('theming-log'); +var theme = require('./theme'); /* istanbul ignore next */ function noop() {} @@ -14,15 +15,24 @@ var levels = [ 'debug', // -LLLL: Logs all log levels. ]; +function consoleLog(s) { + if (s) console.log(s); +} + +function consoleError(s) { + /* istanbul ignore else */ + if (s) console.error(s); +} + function cleanup(log) { levels.forEach(removeListeners); function removeListeners(level) { if (level === 'error') { log.removeListener(level, noop); - log.removeListener(level, fancyLog.error); + log.removeListener(level, consoleError); } else { - log.removeListener(level, fancyLog); + log.removeListener(level, consoleLog); } } } @@ -48,10 +58,12 @@ function toConsole(log, opts) { }) .forEach(function(level) { if (level === 'error') { - log.on(level, fancyLog.error); + log.on(level, consoleError); } else { - log.on(level, fancyLog); + log.on(level, consoleLog); } + + log[level] = themingLog(theme, log[level]); }); } diff --git a/lib/shared/options/make-help.js b/lib/shared/options/make-help.js new file mode 100644 index 00000000..d2b45d14 --- /dev/null +++ b/lib/shared/options/make-help.js @@ -0,0 +1,17 @@ +'use strict'; + +var format = require('theming-log').format; +var theme = require('../log/theme'); +var msgs = require('../log/messages'); + +function makeHelp(parser) { + parser.usage(format(theme, msgs.help.usage)); + + Object.keys(msgs.help.flags).forEach(function(flag) { + parser.describe(flag, format(theme, msgs.help.flags[flag])); + }); + + return parser; +} + +module.exports = makeHelp; diff --git a/lib/shared/options/parser.js b/lib/shared/options/parser.js index 67594a05..52aa7e07 100644 --- a/lib/shared/options/parser.js +++ b/lib/shared/options/parser.js @@ -1,128 +1,84 @@ 'use strict'; -var chalk = require('chalk'); var yargs = require('yargs'); -var usage = - '\n' + chalk.bold('Usage:') + - ' gulp ' + chalk.blue('[options]') + ' tasks'; - var options = { help: { alias: 'h', type: 'boolean', - desc: chalk.gray( - 'Show this help.'), }, version: { alias: 'v', type: 'boolean', - desc: chalk.gray( - 'Print the global and local gulp versions.'), }, preload: { type: 'string', requiresArg: true, - desc: chalk.gray( - 'Will preload a module before running the gulpfile. ' + - 'This is useful for transpilers but also has other applications.'), }, gulpfile: { alias: 'f', type: 'string', requiresArg: true, - desc: chalk.gray( - 'Manually set path of gulpfile. Useful if you have multiple gulpfiles. ' + - 'This will set the CWD to the gulpfile directory as well.'), }, cwd: { type: 'string', requiresArg: true, - desc: chalk.gray( - 'Manually set the CWD. The search for the gulpfile, ' + - 'as well as the relativity of all requires will be from here.'), }, tasks: { alias: 'T', type: 'boolean', - desc: chalk.gray( - 'Print the task dependency tree for the loaded gulpfile.'), }, 'tasks-simple': { type: 'boolean', - desc: chalk.gray( - 'Print a plaintext list of tasks for the loaded gulpfile.'), }, 'tasks-json': { - desc: chalk.gray( - 'Print the task dependency tree, ' + - 'in JSON format, for the loaded gulpfile.'), }, 'tasks-depth': { alias: 'depth', type: 'number', requiresArg: true, default: undefined, // To detect if this cli option is specified. - desc: chalk.gray( - 'Specify the depth of the task dependency tree.'), }, 'compact-tasks': { type: 'boolean', default: undefined, // To detect if this cli option is specified. - desc: chalk.gray( - 'Reduce the output of task dependency tree by printing ' + - 'only top tasks and their child tasks.'), }, 'sort-tasks': { type: 'boolean', default: undefined, // To detect if this cli option is specified. - desc: chalk.gray( - 'Will sort top tasks of task dependency tree.'), }, color: { type: 'boolean', - desc: chalk.gray( - 'Will force gulp and gulp plugins to display colors, ' + - 'even when no color support is detected.'), }, 'no-color': { type: 'boolean', - desc: chalk.gray( - 'Will force gulp and gulp plugins to not display colors, ' + - 'even when color support is detected.'), }, silent: { alias: 'S', type: 'boolean', default: undefined, // To detect if this cli option is specified. - desc: chalk.gray( - 'Suppress all gulp logging.'), }, continue: { type: 'boolean', default: undefined, // To detect if this cli option is specified. - desc: chalk.gray( - 'Continue execution of tasks upon failure.'), }, series: { type: 'boolean', default: undefined, // To detect if this cli option is specified. - desc: chalk.gray( - 'Run tasks given on the CLI in series (the default is parallel).'), }, 'log-level': { alias: 'L', // Type isn't needed because count acts as a boolean count: true, default: undefined, // To detect if this cli option is specified. - desc: chalk.gray( - 'Set the loglevel. -L for least verbose and -LLLL for most verbose. ' + - '-LLL is default.'), } }; var parser = yargs .help(false).version(false).detectLocale(false) - .usage(usage).options(options); + .showHelpOnFail(false) + .exitProcess(false) + .fail(function(msg) { throw new Error(msg); }) + .options(options); module.exports = parser; diff --git a/lib/versioned/^3.7.0/index.js b/lib/versioned/^3.7.0/index.js index a5cc2a9f..321493a9 100644 --- a/lib/versioned/^3.7.0/index.js +++ b/lib/versioned/^3.7.0/index.js @@ -1,10 +1,12 @@ 'use strict'; var fs = require('fs'); - var log = require('gulplog'); var stdout = require('mute-stdout'); -var chalk = require('chalk'); + +var msgs = require('../../shared/log/messages'); +var theme = require('../../shared/log/theme'); +var format = require('theming-log').format; var taskTree = require('./task-tree'); var copyTree = require('../../shared/log/copy-tree'); @@ -37,7 +39,7 @@ function execute(env) { exit(1); } - log.info('Using gulpfile', chalk.magenta(tildify(env.configPath))); + log.info(msgs.info.usingGulpfile, tildify(env.configPath)); var gulpInst = require(env.modulePath); logEvents(gulpInst); @@ -53,22 +55,14 @@ function execute(env) { } if (opts.tasks) { tree = taskTree(gulpInst.tasks); - if (env.config.description && typeof env.config.description === 'string') { - tree.label = env.config.description; - } else { - tree.label = 'Tasks for ' + chalk.magenta(tildify(env.configPath)); - } + tree.label = tildify(env.configPath); return logTasks(tree, opts, function(task) { return gulpInst.tasks[task].fn; }); } if (opts.tasksJson) { tree = taskTree(gulpInst.tasks); - if (env.config.description && typeof env.config.description === 'string') { - tree.label = env.config.description; - } else { - tree.label = 'Tasks for ' + tildify(env.configPath); - } + tree.label = format(theme, msgs.tasksJson.description, tildify(env.configPath)); var output = JSON.stringify(copyTree(tree, opts)); diff --git a/lib/versioned/^3.7.0/log/events.js b/lib/versioned/^3.7.0/log/events.js index a20de7ce..09a428cf 100644 --- a/lib/versioned/^3.7.0/log/events.js +++ b/lib/versioned/^3.7.0/log/events.js @@ -2,8 +2,7 @@ var log = require('gulplog'); var formatTime = require('../../../shared/log/format-hrtime'); -var chalk = require('chalk'); - +var msgs = require('../../../shared/log/messages'); var exit = require('../../../shared/exit'); var formatError = require('../format-error'); @@ -26,33 +25,22 @@ function logEvents(gulpInst) { gulpInst.on('task_start', function(e) { // TODO: batch these // so when 5 tasks start at once it only logs one time with all 5 - log.info('Starting', '\'' + chalk.cyan(e.task) + '\'...'); + log.info(msgs.info.taskStart, e.task); }); gulpInst.on('task_stop', function(e) { var time = formatTime(e.hrDuration); - log.info( - 'Finished', '\'' + chalk.cyan(e.task) + '\'', - 'after', chalk.magenta(time) - ); + log.info(msgs.info.taskStop, e.task, time); }); gulpInst.on('task_err', function(e) { var msg = formatError(e); var time = formatTime(e.hrDuration); - log.error( - '\'' + chalk.cyan(e.task) + '\'', - chalk.red('errored after'), - chalk.magenta(time) - ); - log.error(msg); + log.error(msgs.error.taskError, e.task, time, Boolean(msg), msg); }); gulpInst.on('task_not_found', function(err) { - log.error( - chalk.red('Task \'' + err.task + '\' is not in your gulpfile') - ); - log.error('Please check the documentation for proper gulpfile formatting'); + log.error(msgs.error.taskNotFound, err.task); exit(1); }); } diff --git a/lib/versioned/^4.0.0-alpha.1/index.js b/lib/versioned/^4.0.0-alpha.1/index.js index c9c5ffc3..8e036922 100644 --- a/lib/versioned/^4.0.0-alpha.1/index.js +++ b/lib/versioned/^4.0.0-alpha.1/index.js @@ -1,10 +1,12 @@ 'use strict'; var fs = require('fs'); - var log = require('gulplog'); var stdout = require('mute-stdout'); -var chalk = require('chalk'); + +var msgs = require('../../shared/log/messages'); +var theme = require('../../shared/log/theme'); +var format = require('theming-log').format; var exit = require('../../shared/exit'); var tildify = require('../../shared/tildify'); @@ -13,6 +15,7 @@ var logTasks = require('../../shared/log/tasks'); var logEvents = require('../^4.0.0/log/events'); var logSyncTask = require('../^4.0.0/log/sync-task'); var logTasksSimple = require('../^4.0.0/log/tasks-simple'); +var checkTaskNotFound = require('../^4.0.0/log/check-task-not-found'); var registerExports = require('../../shared/register-exports'); var copyTree = require('../../shared/log/copy-tree'); @@ -53,23 +56,16 @@ function execute(env) { } if (opts.tasks) { tree = {}; - if (env.config.description && typeof env.config.description === 'string') { - tree.label = env.config.description; - } else { - tree.label = 'Tasks for ' + chalk.magenta(tildify(env.configPath)); - } + tree.label = tildify(env.configPath); tree.nodes = gulpInst.tree({ deep: true }); + return logTasks(tree, opts, function(taskname) { return gulpInst.task(taskname); }); } if (opts.tasksJson) { tree = {}; - if (env.config.description && typeof env.config.description === 'string') { - tree.label = env.config.description; - } else { - tree.label = 'Tasks for ' + tildify(env.configPath); - } + tree.label = format(theme, msgs.tasksJson.description, tildify(env.configPath)); tree.nodes = gulpInst.tree({ deep: true }); var output = JSON.stringify(copyTree(tree, opts)); @@ -79,7 +75,7 @@ function execute(env) { return fs.writeFileSync(opts.tasksJson, output, 'utf-8'); } try { - log.info('Using gulpfile', chalk.magenta(tildify(env.configPath))); + log.info(msgs.info.usingGulpfile, tildify(env.configPath)); var runMethod = opts.series ? 'series' : 'parallel'; gulpInst[runMethod](toRun)(function(err) { if (err) { @@ -87,8 +83,12 @@ function execute(env) { } }); } catch (err) { - log.error(chalk.red(err.message)); - log.error('To list available tasks, try running: gulp --tasks'); + var task = checkTaskNotFound(err); + if (task) { + log.error(msgs.error.taskNotFound, task.target, Boolean(task.similar), task.similar); + } else { + log.error(msgs.error.failToRun, err.message); + } exit(1); } }); diff --git a/lib/versioned/^4.0.0-alpha.2/index.js b/lib/versioned/^4.0.0-alpha.2/index.js index 3d1763a6..ab787e1d 100644 --- a/lib/versioned/^4.0.0-alpha.2/index.js +++ b/lib/versioned/^4.0.0-alpha.2/index.js @@ -1,10 +1,12 @@ 'use strict'; var fs = require('fs'); - var log = require('gulplog'); var stdout = require('mute-stdout'); -var chalk = require('chalk'); + +var msgs = require('../../shared/log/messages'); +var theme = require('../../shared/log/theme'); +var format = require('theming-log').format; var exit = require('../../shared/exit'); var tildify = require('../../shared/tildify'); @@ -13,6 +15,7 @@ var logTasks = require('../../shared/log/tasks'); var logEvents = require('../^4.0.0/log/events'); var logSyncTask = require('../^4.0.0/log/sync-task'); var logTasksSimple = require('../^4.0.0/log/tasks-simple'); +var checkTaskNotFound = require('../^4.0.0/log/check-task-not-found'); var registerExports = require('../../shared/register-exports'); var copyTree = require('../../shared/log/copy-tree'); @@ -55,21 +58,12 @@ function execute(env) { } if (opts.tasks) { tree = gulpInst.tree({ deep: true }); - if (env.config.description && typeof env.config.description === 'string') { - tree.label = env.config.description; - } else { - tree.label = 'Tasks for ' + chalk.magenta(tildify(env.configPath)); - } - + tree.label = tildify(env.configPath); return logTasks(tree, opts, getTask(gulpInst)); } if (opts.tasksJson) { tree = gulpInst.tree({ deep: true }); - if (env.config.description && typeof env.config.description === 'string') { - tree.label = env.config.description; - } else { - tree.label = 'Tasks for ' + tildify(env.configPath); - } + tree.label = format(theme, msgs.tasksJson.description, tildify(env.configPath)); var output = JSON.stringify(copyTree(tree, opts)); @@ -79,7 +73,7 @@ function execute(env) { return fs.writeFileSync(opts.tasksJson, output, 'utf-8'); } try { - log.info('Using gulpfile', chalk.magenta(tildify(env.configPath))); + log.info(msgs.info.usingGulpfile, tildify(env.configPath)); var runMethod = opts.series ? 'series' : 'parallel'; gulpInst[runMethod](toRun)(function(err) { if (err) { @@ -87,8 +81,12 @@ function execute(env) { } }); } catch (err) { - log.error(chalk.red(err.message)); - log.error('To list available tasks, try running: gulp --tasks'); + var task = checkTaskNotFound(err); + if (task) { + log.error(msgs.error.taskNotFound, task.target, Boolean(task.similar), task.similar); + } else { + log.error(msgs.error.failToRun, err.message); + } exit(1); } }); diff --git a/lib/versioned/^4.0.0/index.js b/lib/versioned/^4.0.0/index.js index d6883587..a73cf11a 100644 --- a/lib/versioned/^4.0.0/index.js +++ b/lib/versioned/^4.0.0/index.js @@ -1,11 +1,13 @@ 'use strict'; var fs = require('fs'); - var log = require('gulplog'); var stdout = require('mute-stdout'); -var chalk = require('chalk'); +var msgs = require('../../shared/log/messages'); +var theme = require('../../shared/log/theme'); +var format = require('theming-log').format; + var exit = require('../../shared/exit'); var tildify = require('../../shared/tildify'); @@ -13,6 +15,7 @@ var logTasks = require('../../shared/log/tasks'); var logEvents = require('./log/events'); var logSyncTask = require('./log/sync-task'); var logTasksSimple = require('./log/tasks-simple'); +var checkTaskNotFound = require('./log/check-task-not-found'); var registerExports = require('../../shared/register-exports'); var copyTree = require('../../shared/log/copy-tree'); @@ -55,21 +58,12 @@ function execute(env) { } if (opts.tasks) { tree = gulpInst.tree({ deep: true }); - if (env.config.description && typeof env.config.description === 'string') { - tree.label = env.config.description; - } else { - tree.label = 'Tasks for ' + chalk.magenta(tildify(env.configPath)); - } - + tree.label = tildify(env.configPath); return logTasks(tree, opts, getTask(gulpInst)); } if (opts.tasksJson) { tree = gulpInst.tree({ deep: true }); - if (env.config.description && typeof env.config.description === 'string') { - tree.label = env.config.description; - } else { - tree.label = 'Tasks for ' + tildify(env.configPath); - } + tree.label = format(theme, msgs.tasksJson.description, tildify(env.configPath)); var output = JSON.stringify(copyTree(tree, opts)); @@ -79,7 +73,7 @@ function execute(env) { return fs.writeFileSync(opts.tasksJson, output, 'utf-8'); } try { - log.info('Using gulpfile', chalk.magenta(tildify(env.configPath))); + log.info(msgs.info.usingGulpfile, tildify(env.configPath)); var runMethod = opts.series ? 'series' : 'parallel'; gulpInst[runMethod](toRun)(function(err) { if (err) { @@ -87,8 +81,12 @@ function execute(env) { } }); } catch (err) { - log.error(chalk.red(err.message)); - log.error('To list available tasks, try running: gulp --tasks'); + var task = checkTaskNotFound(err); + if (task) { + log.error(msgs.error.taskNotFound, task.target, Boolean(task.similar), task.similar); + } else { + log.error(msgs.error.failToRun, err.message); + } exit(1); } }); diff --git a/lib/versioned/^4.0.0/log/check-task-not-found.js b/lib/versioned/^4.0.0/log/check-task-not-found.js new file mode 100644 index 00000000..e996f212 --- /dev/null +++ b/lib/versioned/^4.0.0/log/check-task-not-found.js @@ -0,0 +1,25 @@ +'use strict'; + +function checkTaskNotFound(err) { + /* istanbul ignore if */ + if (!err || !err.message) { + return undefined; + } + var fixed0 = 'Task never defined: '; + var fixed1 = ' - did you mean? '; + + if (err.message.startsWith(fixed0)) { + var target = err.message.slice(fixed0.length); + var similar = undefined; + + var index = target.indexOf(fixed1); + if (index >= 0) { + similar = target.slice(index + fixed1.length); + target = target.slice(0, index); + } + + return { target: target, similar: similar }; + } +} + +module.exports = checkTaskNotFound; diff --git a/lib/versioned/^4.0.0/log/events.js b/lib/versioned/^4.0.0/log/events.js index 0fb82c5c..0897b88e 100644 --- a/lib/versioned/^4.0.0/log/events.js +++ b/lib/versioned/^4.0.0/log/events.js @@ -2,8 +2,7 @@ var log = require('gulplog'); var formatTime = require('../../../shared/log/format-hrtime'); - -var chalk = require('chalk'); +var msgs = require('../../../shared/log/messages'); var formatError = require('../format-error'); // Wire up logging events @@ -16,34 +15,29 @@ function logEvents(gulpInst) { // TODO: batch these // so when 5 tasks start at once it only logs one time with all 5 var level = evt.branch ? 'debug' : 'info'; - log[level]('Starting', '\'' + chalk.cyan(evt.name) + '\'...'); + log[level](msgs.info.taskStart, evt.name); }); gulpInst.on('stop', function(evt) { var time = formatTime(evt.duration); /* istanbul ignore next */ var level = evt.branch ? 'debug' : 'info'; - log[level]( - 'Finished', '\'' + chalk.cyan(evt.name) + '\'', - 'after', chalk.magenta(time) - ); + log[level](msgs.info.taskStop, evt.name, time); }); gulpInst.on('error', function(evt) { var msg = formatError(evt); - var time = formatTime(evt.duration); - var level = evt.branch ? 'debug' : 'error'; - log[level]( - '\'' + chalk.cyan(evt.name) + '\'', - chalk.red('errored after'), - chalk.magenta(time) - ); + var firstOutput = false; // If we haven't logged this before, log it and add to list if (loggedErrors.indexOf(evt.error) === -1) { - log.error(msg); + firstOutput = true; loggedErrors.push(evt.error); } + + var time = formatTime(evt.duration); + var level = evt.branch ? 'debug' : 'error'; + log[level](msgs.error.taskError, evt.name, time, firstOutput, msg); }); } diff --git a/lib/versioned/^4.0.0/log/sync-task.js b/lib/versioned/^4.0.0/log/sync-task.js index ff380f10..b0719d27 100644 --- a/lib/versioned/^4.0.0/log/sync-task.js +++ b/lib/versioned/^4.0.0/log/sync-task.js @@ -1,7 +1,7 @@ 'use strict'; var log = require('gulplog'); -var chalk = require('chalk'); +var msgs = require('../../../shared/log/messages'); var tasks = {}; @@ -18,13 +18,7 @@ function warn() { process.exitCode = 1; - log.warn( - chalk.red('The following tasks did not complete:'), - chalk.cyan(taskNames) - ); - log.warn( - chalk.red('Did you forget to signal async completion?') - ); + log.warn(msgs.warn.taskNotComplete, taskNames); } function start(e) { diff --git a/package.json b/package.json index 47ff7595..361490ed 100644 --- a/package.json +++ b/package.json @@ -32,13 +32,14 @@ "dependencies": { "chalk": "^4.1.2", "copy-props": "^4.0.0", - "fancy-log": "^2.0.0", "gulplog": "^2.0.1", "interpret": "^3.1.1", "liftoff": "^4.0.0", "mute-stdout": "^2.0.0", "replace-homedir": "^2.0.0", "semver-greatest-satisfied-range": "^2.0.0", + "string-width": "^4.2.3", + "theming-log": "^3.0.0", "v8flags": "^4.0.0", "yargs": "^16.2.0" }, @@ -50,8 +51,8 @@ "eslint-config-gulp": "^5.0.1", "expect": "^27.5.1", "gulp": "^4.0.2", - "marked-man": "^0.7.0", "marked": "^0.7.0", + "marked-man": "^0.7.0", "mocha": "^8.4.0", "nyc": "^15.1.0", "rimraf": "^3.0.2", diff --git a/test/config-description.js b/test/config-description.js deleted file mode 100644 index ac85fd70..00000000 --- a/test/config-description.js +++ /dev/null @@ -1,72 +0,0 @@ -'use strict'; - -var expect = require('expect'); -var exec = require('child_process').exec; -var path = require('path'); -var fs = require('fs'); - -var sliceLines = require('./tool/slice-lines'); -var eraseTime = require('./tool/erase-time'); -var gulp = require('./tool/gulp-cmd'); - -var baseDir = path.join(__dirname, 'fixtures', 'config'); -var expectedDir = path.join(__dirname, 'expected', 'config'); - -describe('config: description', function() { - - it('Should configure with a .gulp.* file in cwd', function(done) { - var opts = { cwd: path.join(baseDir, 'foo/bar') }; - exec(gulp('--tasks'), opts, cb); - - function cb(err, stdout, stderr) { - expect(err).toBeNull(); - expect(stderr).toEqual(''); - var expected = fs.readFileSync(path.join(expectedDir, 'output0.txt'), 'utf-8'); - expect(eraseTime(stdout)).toEqual(expected); - done(err); - } - }); - - it('Should configure with a .gulp.* file in cwd found up', function(done) { - var opts = { cwd: path.join(baseDir, 'foo/bar/baz') }; - exec(gulp('--tasks'), opts, cb); - - function cb(err, stdout, stderr) { - expect(err).toBeNull(); - expect(stderr).toEqual(''); - var expected = fs.readFileSync(path.join(expectedDir, 'output0.txt'), 'utf-8'); - expect(sliceLines(stdout, 1)).toEqual(expected); - done(err); - } - }); - - it('Should configure with a .gulp.* file in cwd even if it is not a project root', function(done) { - var opts = { cwd: path.join(baseDir, 'foo/bar/quux') }; - exec(gulp('--tasks'), opts, cb); - - function cb(err, stdout, stderr) { - expect(err).toBeNull(); - expect(stderr).toEqual(''); - var expected = fs.readFileSync(path.join(expectedDir, 'output2.txt'), 'utf-8'); - expect(sliceLines(stdout, 1)).toEqual(expected); - done(err); - } - }); - - it('Should configure with a .gulp.* file in cwd by --cwd', function(done) { - var opts = { cwd: path.join(baseDir, 'qux') }; - exec(gulp( - '--tasks', - '--gulpfile ../foo/bar/gulpfile.js', - '--cwd .' - ), opts, cb); - - function cb(err, stdout, stderr) { - expect(err).toBeNull(); - expect(stderr).toEqual(''); - var expected = fs.readFileSync(path.join(expectedDir, 'output1.txt'), 'utf-8'); - expect(eraseTime(stdout)).toEqual(expected); - done(err); - } - }); -}); diff --git a/test/config-theme-and-msgs.js b/test/config-theme-and-msgs.js new file mode 100644 index 00000000..4bb1a851 --- /dev/null +++ b/test/config-theme-and-msgs.js @@ -0,0 +1,561 @@ +'use strict'; + +var expect = require('expect'); +var exec = require('child_process').exec; +var path = require('path'); +var fs = require('fs'); +var os = require('os'); + +var tildify = require('../lib/shared/tildify'); + +var baseDir = path.join(__dirname, 'fixtures/config/theming'); +var expectedDir = path.join(__dirname, 'expected/config/theming'); + +var eraseTime = require('./tool/erase-time'); +var eraseLapse = require('./tool/erase-lapse'); +var gulp = require('./tool/gulp-cmd'); + +describe('config: theme.* & msgs.*', function() { + + it('Should change help.usage with .gulp.*', function(done) { + var cwd = path.join(baseDir, 'help/usage'); + var expected = fs.readFileSync(path.join(expectedDir, 'help/usage/help.txt'), 'utf8'); + + var opts = { cwd: cwd }; + exec(gulp('--help'), opts, cb); + + function cb(err, stdout, stderr) { + expect(err).toBeNull(); + expect(stderr).toEqual(''); + expect(stdout).toEqual(expected); + done(err); + } + }); + + it('Should change help.flags.* with .gulp.*', function(done) { + var cwd = path.join(baseDir, 'help/flags'); + var expected = fs.readFileSync(path.join(expectedDir, 'help/flags/help.txt'), 'utf8'); + + var opts = { cwd: cwd }; + exec(gulp('--help'), opts, cb); + + function cb(err, stdout, stderr) { + expect(err).toBeNull(); + expect(stderr).toEqual(''); + expect(stdout).toEqual(expected); + done(err); + } + }); + + it('Should change tasks.description with .gulp.*', function(done) { + var cwd = path.join(baseDir, 'tasks/description'); + var gulpfile = tildify(path.join(cwd, 'gulpfile.js')); + var expected = '** ' + gulpfile + ' **\n' + + '└── default\n'; + + var opts = { cwd: cwd }; + exec(gulp('--tasks'), opts, cb); + + function cb(err, stdout, stderr) { + expect(err).toBeNull(); + expect(stderr).toEqual(''); + expect(stdout).toEqual(expected); + done(err); + } + }); + + it('Should remove task.gulpfile line output with .gulp.*', function(done) { + var cwd = path.join(baseDir, 'tasks/description/remove'); + var expected = '└── default\n'; + + var opts = { cwd: cwd }; + exec(gulp('--tasks'), opts, cb); + + function cb(err, stdout, stderr) { + expect(err).toBeNull(); + expect(stderr).toEqual(''); + expect(stdout).toEqual(expected); + done(err); + } + }); + + it('Should change tasks.topTask with .gulp.*', function(done) { + var cwd = path.join(baseDir, 'tasks/topTask'); + var gulpfile = tildify(path.join(cwd, 'gulpfile.js')); + var expected = 'Tasks for ' + gulpfile + '\n' + + '├─┬ **default** This is default task\n' + + '│ │ --ghi …is a flag for default task\n' + + '│ └─┬ \n' + + '│ ├── taskA\n' + + '│ └── taskB\n' + + '├── **taskA** This is task A\n' + + '│ --abc …is a flag for task A\n' + + '└── **taskB** This is task B\n' + + ' --def …is a flag for task B\n'; + + var opts = { cwd: cwd }; + exec(gulp('--tasks'), opts, cb); + + function cb(err, stdout, stderr) { + expect(err).toBeNull(); + expect(stderr).toEqual(''); + expect(stdout).toEqual(expected); + done(err); + } + }); + + it('Should change tasks.option with .gulp.*', function(done) { + var cwd = path.join(baseDir, 'tasks/option'); + var gulpfile = tildify(path.join(cwd, 'gulpfile.js')); + var expected = 'Tasks for ' + gulpfile + '\n' + + '├─┬ default This is default task\n' + + '│ │ **--ghi** » is a flag for default task\n' + + '│ └─┬ \n' + + '│ ├── taskA\n' + + '│ └── taskB\n' + + '├── taskA This is task A\n' + + '│ **--abc** » is a flag for task A\n' + + '└── taskB This is task B\n' + + ' **--def** » is a flag for task B\n'; + + var opts = { cwd: cwd }; + exec(gulp('--tasks'), opts, cb); + + function cb(err, stdout, stderr) { + expect(err).toBeNull(); + expect(stderr).toEqual(''); + expect(stdout).toEqual(expected); + done(err); + } + }); + + it('Should change tasks.childTask with .gulp.*', function(done) { + var cwd = path.join(baseDir, 'tasks/childTask'); + var gulpfile = tildify(path.join(cwd, 'gulpfile.js')); + var expected = 'Tasks for ' + gulpfile + '\n' + + '├─┬ default This is default task\n' + + '│ │ --ghi …is a flag for default task\n' + + '│ └─┬ ****\n' + + '│ ├── **taskA**\n' + + '│ └── **taskB**\n' + + '├── taskA This is task A\n' + + '│ --abc …is a flag for task A\n' + + '└── taskB This is task B\n' + + ' --def …is a flag for task B\n'; + + var opts = { cwd: cwd }; + exec(gulp('--tasks'), opts, cb); + + function cb(err, stdout, stderr) { + expect(err).toBeNull(); + expect(stderr).toEqual(''); + expect(stdout).toEqual(expected); + done(err); + } + }); + + it('Should change tasksJson.gulpfile with .gulp.*', function(done) { + var cwd = path.join(baseDir, 'tasksJson/description'); + var gulpfile = tildify(path.join(cwd, 'gulpfile.js')); + var expected = JSON.stringify({ + label: '** ' + gulpfile + ' **', + nodes: [{ + label: 'default', + type: 'task', + nodes: [], + }], + }) + '\n'; + + var opts = { cwd: cwd }; + exec(gulp('--tasks-json'), opts, cb); + + function cb(err, stdout, stderr) { + expect(err).toBeNull(); + expect(stderr).toEqual(''); + expect(stdout).toEqual(expected); + done(err); + } + }); + + it('Should change info.preloadBefore with .gulp.*', function(done) { + var cwd = path.join(baseDir, 'info/preloadBefore'); + var gulpfile = tildify(path.join(cwd, 'gulpfile.js')); + var expected = 'PRELOADING **./preload**\n' + + 'Preloaded external module: ./preload\n' + + 'Using gulpfile ' + gulpfile + '\n' + + 'Starting \'default\'...\n' + + 'Finished \'default\' after ?\n'; + + var opts = { cwd: cwd }; + exec(gulp('--preload ./preload'), opts, cb); + + function cb(err, stdout, stderr) { + expect(err).toBeNull(); + expect(stderr).toEqual(''); + expect(eraseLapse(eraseTime(stdout))).toEqual(expected); + done(err); + } + }); + + it('Should change info.preloadSuccess with .gulp.*', function(done) { + var cwd = path.join(baseDir, 'info/preloadSuccess'); + var gulpfile = tildify(path.join(cwd, 'gulpfile.js')); + var expected = 'Preloading external module: ./preload\n' + + 'PRELOADDED **./preload**\n' + + 'Using gulpfile ' + gulpfile + '\n' + + 'Starting \'default\'...\n' + + 'Finished \'default\' after ?\n'; + + var opts = { cwd: cwd }; + exec(gulp('--preload ./preload'), opts, cb); + + function cb(err, stdout, stderr) { + expect(err).toBeNull(); + expect(stderr).toEqual(''); + expect(eraseLapse(eraseTime(stdout))).toEqual(expected); + done(err); + } + }); + + it('Should change info.loaderSuccess with .gulp.*', function(done) { + this.timeout(0); + + var cwd = path.join(baseDir, 'info/loaderSuccess'); + var gulpfile = tildify(path.join(cwd, 'gulpfile.babel.js')); + var expected = 'LOADED **@babel/register**\n' + + 'Using gulpfile ' + gulpfile + '\n' + + 'Starting \'default\'...\n' + + 'Finished \'default\' after ?\n'; + + var opts = { cwd: cwd }; + exec(gulp('-f gulpfile.babel.js'), opts, cb); + + function cb(err, stdout, stderr) { + expect(err).toBeNull(); + expect(stderr).toEqual(''); + expect(eraseLapse(eraseTime(stdout))).toEqual(expected); + done(err); + } + }); + + it('Should change info.respawn with .gulp.*', function(done) { + var cwd = path.join(baseDir, 'info/respawn'); + var gulpfile = tildify(path.join(cwd, 'gulpfile.js')); + var expected = 'RESPAWN BY **--lazy**\n' + + 'Using gulpfile ' + gulpfile + '\n' + + 'Starting \'default\'...\n' + + 'Finished \'default\' after ?\n'; + + var opts = { cwd: cwd }; + exec(gulp('--lazy'), opts, cb); + + function cb(err, stdout, stderr) { + expect(err).toBeNull(); + expect(stderr).toEqual(''); + expect(eraseLapse(eraseTime(stdout))).toEqual(expected); + done(err); + } + }); + + it('Should change info.cwdChanged with .gulp.*', function(done) { + var cwd = path.join(baseDir, 'info/cwdChanged'); + var gulpfile = tildify(path.join(cwd, 'gulpfile.js')); + var expected = 'CHANGE CWD TO **' + tildify(cwd) + '**\n' + + 'Using gulpfile ' + gulpfile + '\n' + + 'Starting \'default\'...\n' + + 'Finished \'default\' after ?\n'; + + var opts = { cwd: baseDir }; + exec(gulp('--cwd ' + cwd), opts, cb); + + function cb(err, stdout, stderr) { + expect(err).toBeNull(); + expect(stderr).toEqual(''); + expect(eraseLapse(eraseTime(stdout))).toEqual(expected); + done(err); + } + }); + + it('Should change info.usingGulpfile with .gulp.*', function(done) { + var cwd = path.join(baseDir, 'info/usingGulpfile'); + var gulpfile = tildify(path.join(cwd, 'gulpfile.js')); + var expected = 'USING GULPFILE **' + gulpfile + '**\n' + + 'Starting \'default\'...\n' + + 'Finished \'default\' after ?\n'; + + var opts = { cwd: cwd }; + exec(gulp(), opts, cb); + + function cb(err, stdout, stderr) { + expect(err).toBeNull(); + expect(stderr).toEqual(''); + expect(eraseLapse(eraseTime(stdout))).toEqual(expected); + done(err); + } + }); + + it('Should change info.taskStart with .gulp.*', function(done) { + var cwd = path.join(baseDir, 'info/taskStart'); + var gulpfile = tildify(path.join(cwd, 'gulpfile.js')); + var expected = 'Using gulpfile ' + gulpfile + '\n' + + 'START **default**\n' + + 'Finished \'default\' after ?\n'; + + var opts = { cwd: cwd }; + exec(gulp(), opts, cb); + + function cb(err, stdout, stderr) { + expect(err).toBeNull(); + expect(stderr).toEqual(''); + expect(eraseLapse(eraseTime(stdout))).toEqual(expected); + done(err); + } + }); + + it('Should change info.taskStop with .gulp.*', function(done) { + var cwd = path.join(baseDir, 'info/taskStop'); + var gulpfile = tildify(path.join(cwd, 'gulpfile.js')); + var expected = 'Using gulpfile ' + gulpfile + '\n' + + 'Starting \'default\'...\n' + + 'STOP **default**\n'; + + var opts = { cwd: cwd }; + exec(gulp(), opts, cb); + + function cb(err, stdout, stderr) { + expect(err).toBeNull(); + expect(stderr).toEqual(''); + expect(eraseTime(stdout)).toEqual(expected); + done(err); + } + }); + + it('Should change warn.preloadFailure with .gulp.*', function(done) { + var cwd = path.join(baseDir, 'warn/preloadFailure'); + var gulpfile = tildify(path.join(cwd, 'gulpfile.js')); + var expected = 'Preloading external module: null-module\n' + + 'FAILED TO PRELOAD **null-module**\n' + + 'Using gulpfile ' + gulpfile + '\n' + + 'Starting \'default\'...\n' + + 'Finished \'default\' after ?\n'; + + var opts = { cwd: cwd }; + exec(gulp('--preload null-module'), opts, cb); + + function cb(err, stdout, stderr) { + expect(err).toBeNull(); + expect(stderr).toEqual(''); + expect(eraseLapse(eraseTime(stdout))).toEqual(expected); + done(err); + } + }); + + it('Should change warn.loaderFailure with .gulp.*', function(done) { + var cwd = path.join(baseDir, 'warn/loaderFailure'); + var expected = 'FAIL TO LOAD **coffeescript/register**\n'; + + var opts = { cwd: cwd }; + exec(gulp('-f gulpfile.coffee'), opts, cb); + + function cb(err, stdout, stderr) { + expect(err).not.toBeNull(); + expect(stderr).not.toEqual(''); + expect(eraseTime(stdout)).toEqual(expected); + done(); + } + }); + + it('Should change warn.taskNotComplete with .gulp.*', function(done) { + var cwd = path.join(baseDir, 'warn/taskNotComplete'); + var gulpfile = tildify(path.join(cwd, 'gulpfile.js')); + var expected = 'Using gulpfile ' + gulpfile + '\n' + + 'Starting \'default\'...\n' + + 'TASK **default** DID NOT COMPLETE\n'; + + var opts = { cwd: cwd }; + exec(gulp(), opts, cb); + + function cb(err, stdout, stderr) { + expect(err).not.toBeNull(); + expect(stderr).toEqual(''); + expect(eraseTime(stdout)).toEqual(expected); + done(); + } + }); + + it('Should change error.failToParseCliOpts with .gulp.*', function(done) { + var cwd = path.join(baseDir, 'error/failToParseCliOpts'); + var expected = fs.readFileSync(path.join(expectedDir, 'error/failToParseCliOpts/help.txt'), 'utf8'); + + var opts = { cwd: cwd }; + exec(gulp('-f'), opts, cb); + + function cb(err, stdout, stderr) { + expect(err).not.toBeNull(); + expect(stdout).toEqual(''); + expect(stderr).toEqual(expected); + done(); + } + }); + + it('Should change error.gulpNotFound with .gulp.*', function(done) { + var dir = path.join(baseDir, 'error/gulpNotFound'); + var cwd = os.tmpdir(); + fs.copyFileSync(path.join(dir, '.gulp.js'), path.join(cwd, '.gulp.js')); + + var opts = { cwd: cwd }; + exec(gulp(), opts, cb); + + if (os.platform() === 'darwin') { + cwd = path.join('/private', cwd); + } + var expected = 'GULP NOT FOUND IN **' + cwd + '**\n'; + + function cb(err, stdout, stderr) { + try { + expect(err).not.toBeNull(); + expect(stdout).toEqual(''); + expect(stderr).toEqual(expected); + done(); + } finally { + fs.unlinkSync(path.join(cwd, '.gulp.js')); + } + } + }); + + it('Should change error.nodeModulesNotFound with .gulp.*', function(done) { + var dir = path.join(baseDir, 'error/nodeModulesNotFound'); + var cwd = os.tmpdir(); + fs.copyFileSync(path.join(dir, '.gulp.js'), path.join(cwd, '.gulp.js')); + fs.copyFileSync(path.join(dir, 'package.json'), path.join(cwd, 'package.json')); + var opts = { cwd: cwd }; + exec(gulp(), opts, cb); + + if (os.platform() === 'darwin') { + cwd = path.join('/private', cwd); + } + var expected = 'LOCAL MODULE NOT FOUND **' + cwd + '**\n'; + + function cb(err, stdout, stderr) { + try { + expect(err).not.toBeNull(); + expect(stdout).toEqual(''); + expect(stderr).toEqual(expected); + done(); + } finally { + fs.unlinkSync(path.join(cwd, '.gulp.js')); + fs.unlinkSync(path.join(cwd, 'package.json')); + } + } + }); + + it('Should change error.gulpfileNotFound with .gulp.*', function(done) { + var cwd = path.join(baseDir, 'error/gulpfileNotFound'); + var expected = 'NO GULPFILE\n'; + + var opts = { cwd: cwd }; + exec(gulp(), opts, cb); + + function cb(err, stdout, stderr) { + expect(err).not.toBeNull(); + expect(stdout).toEqual(''); + expect(eraseTime(stderr)).toEqual(expected); + done(); + } + }); + + it('Should change error.badGulpVersion with .gulp.*', function(done) { + var cwd = path.join(baseDir, 'error/badGulpVersion'); + var expected = 'BAD GULP VERSION **1.2.3**\n'; + + var opts = { cwd: cwd }; + exec(gulp(), opts, cb); + + function cb(err, stdout, stderr) { + expect(err).not.toBeNull(); + expect(stdout).toEqual(''); + expect(eraseTime(stderr)).toEqual(expected); + done(); + } + }); + + it('Should change error.taskError with .gulp.*', function(done) { + var cwd = path.join(baseDir, 'error/taskError'); + var gulpfile = tildify(path.join(cwd, 'gulpfile.js')); + var expectedStdout = 'Using gulpfile ' + gulpfile + '\n' + + 'Starting \'default\'...\n'; + var expectedStderr = 'TASK ERROR: **default**\n'; + + var opts = { cwd: cwd }; + exec(gulp(), opts, cb); + + function cb(err, stdout, stderr) { + expect(err).not.toBeNull(); + expect(eraseTime(stderr)).toEqual(expectedStderr); + expect(eraseTime(stdout)).toEqual(expectedStdout); + done(); + } + }); + + it('Should change error.taskNotFound with .gulp.*', function(done) { + var cwd = path.join(baseDir, 'error/taskNotFound'); + var gulpfile = tildify(path.join(cwd, 'gulpfile.js')); + var expectedStdout = 'Using gulpfile ' + gulpfile + '\n'; + var expectedStderr = 'TASK IS NOT FOUND: **defaults** SIMILAR ##default##'; + + var opts = { cwd: cwd }; + exec(gulp('defaults'), opts, cb); + + function cb(err, stdout, stderr) { + expect(err).not.toBeNull(); + expect(eraseTime(stderr)).toMatch(expectedStderr); + expect(eraseTime(stdout)).toEqual(expectedStdout); + done(); + } + }); + + it('Should change error.failToRun with .gulp.*', function(done) { + var cwd = path.join(baseDir, 'error/failToRun'); + var expected = 'FAIL TO RUN\n'; + + var opts = { cwd: cwd }; + exec(gulp(), opts, cb); + + function cb(err, stdout, stderr) { + expect(err).not.toBeNull(); + expect(stderr).toEqual(expected); + expect(stdout).toEqual(''); + done(); + } + }); + + it('Should change error.noCompletionType with .gulp.*', function(done) { + var cwd = path.join(baseDir, 'error/noCompletionType'); + var expected = 'NO COMPLETION TYPE'; + + var opts = { cwd: cwd }; + exec(gulp('--completion'), opts, cb); + + function cb(err, stdout, stderr) { + expect(err).not.toBeNull(); + expect(stderr).toMatch(expected); + expect(stdout).toEqual(''); + done(); + } + }); + + it('Should change error.unknownCompletionType with .gulp.*', function(done) { + var cwd = path.join(baseDir, 'error/unknownCompletionType'); + var expected = 'GULP COMPLETION TYPE **xxx** IS NOT FOUND\n'; + + var opts = { cwd: cwd }; + exec(gulp('--completion=xxx'), opts, cb); + + function cb(err, stdout, stderr) { + expect(err).not.toBeNull(); + expect(stderr).toEqual(''); + expect(stdout).toEqual(expected); + done(); + } + }); +}); diff --git a/test/execution-errors.js b/test/execution-errors.js index 769832a9..7b2fd1ec 100644 --- a/test/execution-errors.js +++ b/test/execution-errors.js @@ -4,6 +4,7 @@ var expect = require('expect'); var exec = require('child_process').exec; var path = require('path'); var os = require('os'); +var fs = require('fs'); var tildify = require('../lib/shared/tildify'); @@ -29,6 +30,21 @@ describe('execution error', function() { } }); + it('should output an error if a task is not defined but a similar task is found', function(done) { + var opts = { cwd: path.join(__dirname, './fixtures/gulpfiles') }; + exec(gulp('test0'), opts, cb); + + function cb(err, stdout, stderr) { + expect(err).not.toBeNull(); + expect(err.code).toEqual(1); + expect(eraseTime(stdout)).toMatch('Using gulpfile '); + expect(eraseTime(stderr)).toEqual( + 'Task never defined: test0 - did you mean? test1, test2, test3, test4, test5, test6, test7, test8\n' + + 'To list available tasks, try running: gulp --tasks\n'); + done(); + } + }); + it('should output an error if gulp version is unsupported', function(done) { var opts = { cwd: path.join(__dirname, './fixtures/errors/bad-gulp-version') }; exec(gulp(), opts, cb); @@ -42,7 +58,7 @@ describe('execution error', function() { } }); - it('should output an error if gulp is not found', function(done) { + it('should output an error if gulp is not found (npm)', function(done) { var opts = { cwd: os.tmpdir() }; exec(gulp(), opts, cb); @@ -55,6 +71,79 @@ describe('execution error', function() { } }); + it('should output an error if gulp is not found (yarn)', function(done) { + var cwd = os.tmpdir(); + var yarnOrig= path.join(__dirname, 'fixtures/errors/yarn/yarn.lock'); + var yarnLock = path.join(cwd, 'yarn.lock'); + + fs.copyFileSync(yarnOrig, yarnLock); + + var opts = { cwd: cwd }; + exec(gulp(), opts, cb); + + function cb(err, stdout, stderr) { + try { + expect(err).not.toBeNull(); + expect(err.code).toEqual(1); + expect(sliceLines(stderr, 0, 1)).toMatch('Local gulp not found in '); + expect(sliceLines(stderr, 1, 2)).toEqual('Try running: yarn add gulp'); + done(); + } finally { + fs.unlinkSync(yarnLock); + } + } + }); + + it('should output an error if local modules are not found (npm)', function(done) { + var cwd = os.tmpdir(); + var pkgOrig = path.join(__dirname, 'fixtures/errors/package.json'); + var pkgJson = path.join(cwd, 'package.json'); + + fs.copyFileSync(pkgOrig, pkgJson); + + var opts = { cwd: cwd }; + exec(gulp(), opts, cb); + + function cb(err, stdout, stderr) { + try { + expect(err).not.toBeNull(); + expect(err.code).toEqual(1); + expect(sliceLines(stderr, 0, 1)).toMatch('Local modules not found in '); + expect(sliceLines(stderr, 1, 2)).toEqual('Try running: npm install'); + done(); + } finally { + fs.unlinkSync(pkgJson); + } + } + }); + + it('should output an error if local modules are not found (yarn)', function(done) { + var cwd = os.tmpdir(); + var pkgOrig = path.join(__dirname, 'fixtures/errors/package.json'); + var pkgJson = path.join(cwd, 'package.json'); + var yarnOrig= path.join(__dirname, 'fixtures/errors/yarn/yarn.lock'); + var yarnLock = path.join(cwd, 'yarn.lock'); + + fs.copyFileSync(pkgOrig, pkgJson); + fs.copyFileSync(yarnOrig, yarnLock); + + var opts = { cwd: cwd }; + exec(gulp(), opts, cb); + + function cb(err, stdout, stderr) { + try { + expect(err).not.toBeNull(); + expect(err.code).toEqual(1); + expect(sliceLines(stderr, 0, 1)).toMatch('Local modules not found in '); + expect(sliceLines(stderr, 1, 2)).toEqual('Try running: yarn install'); + done(); + } finally { + fs.unlinkSync(pkgJson); + fs.unlinkSync(yarnLock); + } + } + }); + it('should log a same error once', function(done) { var dir = path.join(__dirname, 'fixtures/gulpfiles'); var gulpfileName = 'gulpfile-dedup-errorlog.js'; diff --git a/test/expected/config/theming/error/failToParseCliOpts/help.txt b/test/expected/config/theming/error/failToParseCliOpts/help.txt new file mode 100644 index 00000000..5d37e6fa --- /dev/null +++ b/test/expected/config/theming/error/failToParseCliOpts/help.txt @@ -0,0 +1,41 @@ +**Not enough arguments following: f** + +Usage: gulp [options] tasks + +Options: + -h, --help Show this help. [boolean] + -v, --version Print the global and local gulp versions.[boolean] + --preload Will preload a module before running the gulpfile. + This is useful for transpilers but also has other + applications. [string] + -f, --gulpfile Manually set path of gulpfile. Useful if you have + multiple gulpfiles. This will set the CWD to the + gulpfile directory as well. [string] + --cwd Manually set the CWD. The search for the gulpfile, + as well as the relativity of all requires will be + from here. [string] + -T, --tasks Print the task dependency tree for the loaded + gulpfile. [boolean] + --tasks-simple Print a plaintext list of tasks for the loaded + gulpfile. [boolean] + --tasks-json Print the task dependency tree, in JSON format, + for the loaded gulpfile. + --tasks-depth, --depth Specify the depth of the task dependency tree. + [number] + --compact-tasks Reduce the output of task dependency tree by + printing only top tasks and their child tasks. + [boolean] + --sort-tasks Will sort top tasks of task dependency tree. + [boolean] + --color Will force gulp and gulp plugins to display + colors, even when no color support is detected. + [boolean] + --no-color Will force gulp and gulp plugins to not display + colors, even when color support is detected. + [boolean] + -S, --silent Suppress all gulp logging. [boolean] + --continue Continue execution of tasks upon failure.[boolean] + --series Run tasks given on the CLI in series (the default + is parallel). [boolean] + -L, --log-level Set the loglevel. -L for least verbose and -LLLL + for most verbose. -LLL is default. [count] diff --git a/test/expected/config/theming/help/flags/help.txt b/test/expected/config/theming/help/flags/help.txt new file mode 100644 index 00000000..3fae82da --- /dev/null +++ b/test/expected/config/theming/help/flags/help.txt @@ -0,0 +1,21 @@ + +Usage: gulp [options] tasks + +Options: + -h, --help **HELP** [boolean] + -v, --version **VERSION** [boolean] + --preload **PRELOAD** [string] + -f, --gulpfile **GULPFILE** [string] + --cwd **CWD** [string] + -T, --tasks **TASKS** [boolean] + --tasks-simple **TASKS SIMPLE** [boolean] + --tasks-json **TASKS JSON** + --tasks-depth, --depth **TASKS DEPTH** [number] + --compact-tasks **COMPACT TASKS** [boolean] + --sort-tasks **SORT_TASKS** [boolean] + --color **COLOR** [boolean] + --no-color **NO COLOR** [boolean] + -S, --silent **SILENT** [boolean] + --continue **CONTINUE** [boolean] + --series **SERIES** [boolean] + -L, --log-level **LOG LEVEL** [count] diff --git a/test/expected/config/theming/help/usage/help.txt b/test/expected/config/theming/help/usage/help.txt new file mode 100644 index 00000000..b03f78bd --- /dev/null +++ b/test/expected/config/theming/help/usage/help.txt @@ -0,0 +1,39 @@ +GULP USAGE + +Options: + -h, --help Show this help. [boolean] + -v, --version Print the global and local gulp versions.[boolean] + --preload Will preload a module before running the gulpfile. + This is useful for transpilers but also has other + applications. [string] + -f, --gulpfile Manually set path of gulpfile. Useful if you have + multiple gulpfiles. This will set the CWD to the + gulpfile directory as well. [string] + --cwd Manually set the CWD. The search for the gulpfile, + as well as the relativity of all requires will be + from here. [string] + -T, --tasks Print the task dependency tree for the loaded + gulpfile. [boolean] + --tasks-simple Print a plaintext list of tasks for the loaded + gulpfile. [boolean] + --tasks-json Print the task dependency tree, in JSON format, + for the loaded gulpfile. + --tasks-depth, --depth Specify the depth of the task dependency tree. + [number] + --compact-tasks Reduce the output of task dependency tree by + printing only top tasks and their child tasks. + [boolean] + --sort-tasks Will sort top tasks of task dependency tree. + [boolean] + --color Will force gulp and gulp plugins to display + colors, even when no color support is detected. + [boolean] + --no-color Will force gulp and gulp plugins to not display + colors, even when color support is detected. + [boolean] + -S, --silent Suppress all gulp logging. [boolean] + --continue Continue execution of tasks upon failure.[boolean] + --series Run tasks given on the CLI in series (the default + is parallel). [boolean] + -L, --log-level Set the loglevel. -L for least verbose and -LLLL + for most verbose. -LLL is default. [count] diff --git a/test/expected/flags-tasks-depth1.txt b/test/expected/flags-tasks-depth1.txt new file mode 100644 index 00000000..d973a446 --- /dev/null +++ b/test/expected/flags-tasks-depth1.txt @@ -0,0 +1,4 @@ +gulp-cli/test/fixtures/gulpfiles +├── taskC +├── taskB +└── default diff --git a/test/fixtures/.gulp.json b/test/fixtures/.gulp.json index 6aad6e7f..c0c87edd 100644 --- a/test/fixtures/.gulp.json +++ b/test/fixtures/.gulp.json @@ -1,3 +1,9 @@ { - "description" : "gulp-cli/test/fixtures" + "log": { + "msgs": { + "tasks": { + "description" : "gulp-cli/test/fixtures" + } + } + } } diff --git a/test/fixtures/config/theming/error/badGulpVersion/.gulp.js b/test/fixtures/config/theming/error/badGulpVersion/.gulp.js new file mode 100644 index 00000000..c2c8c93e --- /dev/null +++ b/test/fixtures/config/theming/error/badGulpVersion/.gulp.js @@ -0,0 +1,12 @@ +module.exports = { + log: { + msgs: { + error: { + badGulpVersion: '{TIMESTAMP}BAD GULP VERSION {GulpVer:{1}}', + }, + }, + theme: { + GulpVer: '**{1}**', + }, + }, +}; diff --git a/test/fixtures/config/theming/error/badGulpVersion/gulpfile.js b/test/fixtures/config/theming/error/badGulpVersion/gulpfile.js new file mode 100644 index 00000000..db73dd16 --- /dev/null +++ b/test/fixtures/config/theming/error/badGulpVersion/gulpfile.js @@ -0,0 +1,3 @@ +exports.default = function(done) { + done(); +} diff --git a/test/fixtures/config/theming/error/badGulpVersion/node_modules/gulp/index.js b/test/fixtures/config/theming/error/badGulpVersion/node_modules/gulp/index.js new file mode 100644 index 00000000..e69de29b diff --git a/test/fixtures/config/theming/error/badGulpVersion/node_modules/gulp/package.json b/test/fixtures/config/theming/error/badGulpVersion/node_modules/gulp/package.json new file mode 100644 index 00000000..dbe8ece4 --- /dev/null +++ b/test/fixtures/config/theming/error/badGulpVersion/node_modules/gulp/package.json @@ -0,0 +1,15 @@ +{ + "name": "gulp", + "description": "Test Package for Testing!", + "version": "1.2.3", + "tags": [ + ], + "files": [ + ], + "licenses": [ + { + "type": "MIT", + "url": "https://raw.githubusercontent.com/gulpjs/gulp/master/LICENSE" + } + ] +} diff --git a/test/fixtures/config/theming/error/failToParseCliOpts/.gulp.js b/test/fixtures/config/theming/error/failToParseCliOpts/.gulp.js new file mode 100644 index 00000000..516acab9 --- /dev/null +++ b/test/fixtures/config/theming/error/failToParseCliOpts/.gulp.js @@ -0,0 +1,9 @@ +module.exports = { + log: { + msgs: { + error: { + failToParseCliOpts: '**{1}**', + }, + }, + }, +}; diff --git a/test/fixtures/config/theming/error/failToRun/.gulp.js b/test/fixtures/config/theming/error/failToRun/.gulp.js new file mode 100644 index 00000000..508aa1e8 --- /dev/null +++ b/test/fixtures/config/theming/error/failToRun/.gulp.js @@ -0,0 +1,10 @@ +module.exports = { + log: { + msgs: { + info: null, // To cause failToRun error forcefully + error: { + failToRun: 'FAIL TO RUN', + }, + }, + }, +}; diff --git a/test/fixtures/config/theming/error/failToRun/gulpfile.js b/test/fixtures/config/theming/error/failToRun/gulpfile.js new file mode 100644 index 00000000..db73dd16 --- /dev/null +++ b/test/fixtures/config/theming/error/failToRun/gulpfile.js @@ -0,0 +1,3 @@ +exports.default = function(done) { + done(); +} diff --git a/test/fixtures/config/theming/error/gulpNotFound/.gulp.js b/test/fixtures/config/theming/error/gulpNotFound/.gulp.js new file mode 100644 index 00000000..285358db --- /dev/null +++ b/test/fixtures/config/theming/error/gulpNotFound/.gulp.js @@ -0,0 +1,12 @@ +module.exports = { + log: { + msgs: { + error: { + gulpNotFound: 'GULP NOT FOUND IN {CwdPath: {1}}', + }, + }, + theme: { + CwdPath: '**{1}**', + }, + }, +}; diff --git a/test/fixtures/config/theming/error/gulpfileNotFound/.gulp.js b/test/fixtures/config/theming/error/gulpfileNotFound/.gulp.js new file mode 100644 index 00000000..0524beae --- /dev/null +++ b/test/fixtures/config/theming/error/gulpfileNotFound/.gulp.js @@ -0,0 +1,9 @@ +module.exports = { + log: { + msgs: { + error: { + gulpfileNotFound: '{TIMESTAMP}NO GULPFILE', + }, + }, + }, +}; diff --git a/test/fixtures/config/theming/error/noCompletionType/.gulp.js b/test/fixtures/config/theming/error/noCompletionType/.gulp.js new file mode 100644 index 00000000..42781159 --- /dev/null +++ b/test/fixtures/config/theming/error/noCompletionType/.gulp.js @@ -0,0 +1,9 @@ +module.exports = { + log: { + msgs: { + error: { + noCompletionType: 'NO COMPLETION TYPE', + }, + }, + }, +}; diff --git a/test/fixtures/config/theming/error/noCompletionType/gulpfile.js b/test/fixtures/config/theming/error/noCompletionType/gulpfile.js new file mode 100644 index 00000000..db73dd16 --- /dev/null +++ b/test/fixtures/config/theming/error/noCompletionType/gulpfile.js @@ -0,0 +1,3 @@ +exports.default = function(done) { + done(); +} diff --git a/test/fixtures/config/theming/error/nodeModulesNotFound/.gulp.js b/test/fixtures/config/theming/error/nodeModulesNotFound/.gulp.js new file mode 100644 index 00000000..4d21fdba --- /dev/null +++ b/test/fixtures/config/theming/error/nodeModulesNotFound/.gulp.js @@ -0,0 +1,12 @@ +module.exports = { + log: { + msgs: { + error: { + nodeModulesNotFound: 'LOCAL MODULE NOT FOUND {Path: {1}}', + }, + }, + theme: { + Path: '**{1}**', + }, + }, +}; diff --git a/test/fixtures/config/theming/error/nodeModulesNotFound/package.json b/test/fixtures/config/theming/error/nodeModulesNotFound/package.json new file mode 100644 index 00000000..109ec6a8 --- /dev/null +++ b/test/fixtures/config/theming/error/nodeModulesNotFound/package.json @@ -0,0 +1,12 @@ +{ + "name": "nodeModulesNotFound", + "version": "1.0.0", + "description": "", + "main": ".gulp.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "ISC" +} diff --git a/test/fixtures/config/theming/error/taskError/.gulp.js b/test/fixtures/config/theming/error/taskError/.gulp.js new file mode 100644 index 00000000..346a9cc3 --- /dev/null +++ b/test/fixtures/config/theming/error/taskError/.gulp.js @@ -0,0 +1,12 @@ +module.exports = { + log: { + msgs: { + error: { + taskError: '{TIMESTAMP}TASK ERROR: {TaskName:{1}}', + }, + }, + theme: { + TaskName: '**{1}**', + }, + }, +}; diff --git a/test/fixtures/config/theming/error/taskError/gulpfile.js b/test/fixtures/config/theming/error/taskError/gulpfile.js new file mode 100644 index 00000000..eeb90fd6 --- /dev/null +++ b/test/fixtures/config/theming/error/taskError/gulpfile.js @@ -0,0 +1,3 @@ +exports.default = function(done) { + throw new Error('FAIL!'); +} diff --git a/test/fixtures/config/theming/error/taskNotFound/.gulp.js b/test/fixtures/config/theming/error/taskNotFound/.gulp.js new file mode 100644 index 00000000..42223bca --- /dev/null +++ b/test/fixtures/config/theming/error/taskNotFound/.gulp.js @@ -0,0 +1,13 @@ +module.exports = { + log: { + msgs: { + error: { + taskNotFound: '{TIMESTAMP}TASK IS NOT FOUND: {TaskName:{1}}{IF:{2}? SIMILAR {SimilarTasks:{3}}}', + }, + }, + theme: { + TaskName: '**{1}**', + SimilarTasks: '##{1}##', + }, + }, +}; diff --git a/test/fixtures/config/theming/error/taskNotFound/gulpfile.js b/test/fixtures/config/theming/error/taskNotFound/gulpfile.js new file mode 100644 index 00000000..db73dd16 --- /dev/null +++ b/test/fixtures/config/theming/error/taskNotFound/gulpfile.js @@ -0,0 +1,3 @@ +exports.default = function(done) { + done(); +} diff --git a/test/fixtures/config/theming/error/unknownCompletionType/.gulp.js b/test/fixtures/config/theming/error/unknownCompletionType/.gulp.js new file mode 100644 index 00000000..71d056a9 --- /dev/null +++ b/test/fixtures/config/theming/error/unknownCompletionType/.gulp.js @@ -0,0 +1,12 @@ +module.exports = { + log: { + msgs: { + error: { + unknownCompletionType: 'GULP COMPLETION TYPE {Type: {1}} IS NOT FOUND', + }, + }, + theme: { + Type: '**{1}**', + }, + }, +}; diff --git a/test/fixtures/config/theming/error/unknownCompletionType/gulpfile.js b/test/fixtures/config/theming/error/unknownCompletionType/gulpfile.js new file mode 100644 index 00000000..db73dd16 --- /dev/null +++ b/test/fixtures/config/theming/error/unknownCompletionType/gulpfile.js @@ -0,0 +1,3 @@ +exports.default = function(done) { + done(); +} diff --git a/test/fixtures/config/theming/help/flags/.gulp.js b/test/fixtures/config/theming/help/flags/.gulp.js new file mode 100644 index 00000000..ea807c89 --- /dev/null +++ b/test/fixtures/config/theming/help/flags/.gulp.js @@ -0,0 +1,30 @@ +module.exports = { + log: { + msgs: { + help: { + flags: { + help: '{help_desc: HELP}', + version: '{help_desc: VERSION}', + preload: '{help_desc: PRELOAD}', + gulpfile: '{help_desc: GULPFILE}', + cwd: '{help_desc: CWD}', + tasks: '{help_desc: TASKS}', + 'tasks-simple': '{help_desc: TASKS SIMPLE}', + 'tasks-json': '{help_desc: TASKS JSON}', + 'tasks-depth': '{help_desc: TASKS DEPTH}', + 'compact-tasks': '{help_desc: COMPACT TASKS}', + 'sort-tasks': '{help_desc: SORT_TASKS}', + color: '{help_desc: COLOR}', + 'no-color': '{help_desc: NO COLOR}', + silent: '{help_desc: SILENT}', + continue: '{help_desc: CONTINUE}', + series: '{help_desc: SERIES}', + 'log-level': '{help_desc: LOG LEVEL}', + }, + }, + }, + theme: { + help_desc: '**{1}**', + }, + }, +}; diff --git a/test/fixtures/config/theming/help/usage/.gulp.js b/test/fixtures/config/theming/help/usage/.gulp.js new file mode 100644 index 00000000..30e6e67d --- /dev/null +++ b/test/fixtures/config/theming/help/usage/.gulp.js @@ -0,0 +1,9 @@ +module.exports = { + log: { + msgs: { + help: { + usage: 'GULP USAGE', + }, + }, + }, +}; diff --git a/test/fixtures/config/theming/info/cwdChanged/.gulp.js b/test/fixtures/config/theming/info/cwdChanged/.gulp.js new file mode 100644 index 00000000..d600f306 --- /dev/null +++ b/test/fixtures/config/theming/info/cwdChanged/.gulp.js @@ -0,0 +1,12 @@ +module.exports = { + log: { + msgs: { + info: { + cwdChanged: '{TIMESTAMP}CHANGE CWD TO {CwdPath: {1}}', + }, + }, + theme: { + CwdPath: '**{1}**', + }, + }, +}; diff --git a/test/fixtures/config/theming/info/cwdChanged/gulpfile.js b/test/fixtures/config/theming/info/cwdChanged/gulpfile.js new file mode 100644 index 00000000..db73dd16 --- /dev/null +++ b/test/fixtures/config/theming/info/cwdChanged/gulpfile.js @@ -0,0 +1,3 @@ +exports.default = function(done) { + done(); +} diff --git a/test/fixtures/config/theming/info/loaderSuccess/.gulp.js b/test/fixtures/config/theming/info/loaderSuccess/.gulp.js new file mode 100644 index 00000000..2a1b62d4 --- /dev/null +++ b/test/fixtures/config/theming/info/loaderSuccess/.gulp.js @@ -0,0 +1,12 @@ +module.exports = { + log: { + msgs: { + info: { + loaderSuccess: 'LOADED {ModuleName: {1}}', + }, + }, + theme: { + ModuleName: '**{1}**', + }, + }, +}; diff --git a/test/fixtures/config/theming/info/loaderSuccess/gulpfile.babel.js b/test/fixtures/config/theming/info/loaderSuccess/gulpfile.babel.js new file mode 100644 index 00000000..db73dd16 --- /dev/null +++ b/test/fixtures/config/theming/info/loaderSuccess/gulpfile.babel.js @@ -0,0 +1,3 @@ +exports.default = function(done) { + done(); +} diff --git a/test/fixtures/config/theming/info/preloadBefore/.gulp.js b/test/fixtures/config/theming/info/preloadBefore/.gulp.js new file mode 100644 index 00000000..53dc5ce6 --- /dev/null +++ b/test/fixtures/config/theming/info/preloadBefore/.gulp.js @@ -0,0 +1,12 @@ +module.exports = { + log: { + msgs: { + info: { + preloadBefore: 'PRELOADING {ModuleName: {1}}', + }, + }, + theme: { + ModuleName: '**{1}**', + }, + }, +}; diff --git a/test/fixtures/config/theming/info/preloadBefore/gulpfile.js b/test/fixtures/config/theming/info/preloadBefore/gulpfile.js new file mode 100644 index 00000000..db73dd16 --- /dev/null +++ b/test/fixtures/config/theming/info/preloadBefore/gulpfile.js @@ -0,0 +1,3 @@ +exports.default = function(done) { + done(); +} diff --git a/test/fixtures/config/theming/info/preloadBefore/preload.js b/test/fixtures/config/theming/info/preloadBefore/preload.js new file mode 100644 index 00000000..3b5d0c74 --- /dev/null +++ b/test/fixtures/config/theming/info/preloadBefore/preload.js @@ -0,0 +1 @@ +global.preload = 'hello preload!'; diff --git a/test/fixtures/config/theming/info/preloadSuccess/.gulp.js b/test/fixtures/config/theming/info/preloadSuccess/.gulp.js new file mode 100644 index 00000000..2226a83d --- /dev/null +++ b/test/fixtures/config/theming/info/preloadSuccess/.gulp.js @@ -0,0 +1,12 @@ +module.exports = { + log: { + msgs: { + info: { + preloadSuccess: 'PRELOADDED {ModuleName: {1}}', + }, + }, + theme: { + ModuleName: '**{1}**', + }, + }, +}; diff --git a/test/fixtures/config/theming/info/preloadSuccess/gulpfile.js b/test/fixtures/config/theming/info/preloadSuccess/gulpfile.js new file mode 100644 index 00000000..db73dd16 --- /dev/null +++ b/test/fixtures/config/theming/info/preloadSuccess/gulpfile.js @@ -0,0 +1,3 @@ +exports.default = function(done) { + done(); +} diff --git a/test/fixtures/config/theming/info/preloadSuccess/preload.js b/test/fixtures/config/theming/info/preloadSuccess/preload.js new file mode 100644 index 00000000..3b5d0c74 --- /dev/null +++ b/test/fixtures/config/theming/info/preloadSuccess/preload.js @@ -0,0 +1 @@ +global.preload = 'hello preload!'; diff --git a/test/fixtures/config/theming/info/respawn/.gulp.js b/test/fixtures/config/theming/info/respawn/.gulp.js new file mode 100644 index 00000000..5be9dccc --- /dev/null +++ b/test/fixtures/config/theming/info/respawn/.gulp.js @@ -0,0 +1,12 @@ +module.exports = { + log: { + msgs: { + info: { + respawn: 'RESPAWN BY {NodeFlag: {1}}', + }, + }, + theme: { + NodeFlag: '**{1}**', + }, + }, +}; diff --git a/test/fixtures/config/theming/info/respawn/gulpfile.js b/test/fixtures/config/theming/info/respawn/gulpfile.js new file mode 100644 index 00000000..db73dd16 --- /dev/null +++ b/test/fixtures/config/theming/info/respawn/gulpfile.js @@ -0,0 +1,3 @@ +exports.default = function(done) { + done(); +} diff --git a/test/fixtures/config/theming/info/taskStart/.gulp.js b/test/fixtures/config/theming/info/taskStart/.gulp.js new file mode 100644 index 00000000..1129f3ad --- /dev/null +++ b/test/fixtures/config/theming/info/taskStart/.gulp.js @@ -0,0 +1,12 @@ +module.exports = { + log: { + msgs: { + info: { + taskStart: '{TIMESTAMP}START {Task: {1}}', + }, + }, + theme: { + Task: '**{1}**', + }, + }, +}; diff --git a/test/fixtures/config/theming/info/taskStart/gulpfile.js b/test/fixtures/config/theming/info/taskStart/gulpfile.js new file mode 100644 index 00000000..db73dd16 --- /dev/null +++ b/test/fixtures/config/theming/info/taskStart/gulpfile.js @@ -0,0 +1,3 @@ +exports.default = function(done) { + done(); +} diff --git a/test/fixtures/config/theming/info/taskStop/.gulp.js b/test/fixtures/config/theming/info/taskStop/.gulp.js new file mode 100644 index 00000000..d3355766 --- /dev/null +++ b/test/fixtures/config/theming/info/taskStop/.gulp.js @@ -0,0 +1,12 @@ +module.exports = { + log: { + msgs: { + info: { + taskStop: '{TIMESTAMP}STOP {Task: {1}}', + }, + }, + theme: { + Task: '**{1}**', + }, + }, +}; diff --git a/test/fixtures/config/theming/info/taskStop/gulpfile.js b/test/fixtures/config/theming/info/taskStop/gulpfile.js new file mode 100644 index 00000000..db73dd16 --- /dev/null +++ b/test/fixtures/config/theming/info/taskStop/gulpfile.js @@ -0,0 +1,3 @@ +exports.default = function(done) { + done(); +} diff --git a/test/fixtures/config/theming/info/usingGulpfile/.gulp.js b/test/fixtures/config/theming/info/usingGulpfile/.gulp.js new file mode 100644 index 00000000..a44460a6 --- /dev/null +++ b/test/fixtures/config/theming/info/usingGulpfile/.gulp.js @@ -0,0 +1,12 @@ +module.exports = { + log: { + msgs: { + info: { + usingGulpfile: '{TIMESTAMP}USING GULPFILE {File:{1}}', + }, + }, + theme: { + File: '**{1}**', + }, + }, +}; diff --git a/test/fixtures/config/theming/info/usingGulpfile/gulpfile.js b/test/fixtures/config/theming/info/usingGulpfile/gulpfile.js new file mode 100644 index 00000000..db73dd16 --- /dev/null +++ b/test/fixtures/config/theming/info/usingGulpfile/gulpfile.js @@ -0,0 +1,3 @@ +exports.default = function(done) { + done(); +} diff --git a/test/fixtures/config/theming/info/version/.gulp.js b/test/fixtures/config/theming/info/version/.gulp.js new file mode 100644 index 00000000..a876e2e2 --- /dev/null +++ b/test/fixtures/config/theming/info/version/.gulp.js @@ -0,0 +1,12 @@ +module.exports = { + log: { + msgs: { + info: { + version: 'gulp-cli {VERSION: v{1}} | gulp {VERSION: v{2}}', + }, + }, + theme: { + VERSION: '@@{1}@@', + }, + }, +}; diff --git a/test/fixtures/config/theming/tasks/childTask/.gulp.js b/test/fixtures/config/theming/tasks/childTask/.gulp.js new file mode 100644 index 00000000..51eb19f6 --- /dev/null +++ b/test/fixtures/config/theming/tasks/childTask/.gulp.js @@ -0,0 +1,12 @@ +module.exports = { + log: { + msgs: { + tasks: { + childTask: '{1}{child_task: {2}}', + } + }, + theme: { + child_task: '**{1}**', + }, + }, +}; diff --git a/test/fixtures/config/theming/tasks/childTask/gulpfile.js b/test/fixtures/config/theming/tasks/childTask/gulpfile.js new file mode 100644 index 00000000..b61b53c3 --- /dev/null +++ b/test/fixtures/config/theming/tasks/childTask/gulpfile.js @@ -0,0 +1,27 @@ +const { series } = require('gulp'); + +function taskA(done) { + done(); +} +taskA.description = 'This is task A'; +taskA.flags = { + '--abc': 'is a flag for task A', +}; + +const taskB = function(done) { + done(); +} +taskB.description = 'This is task B'; +taskB.flags = { + '--def': 'is a flag for task B', +}; + +const defaults = series(taskA, taskB); +defaults.description = 'This is default task'; +defaults.flags = { + '--ghi': 'is a flag for default task', +}; + +exports.default = defaults; +exports.taskA = taskA; +exports.taskB = taskB; diff --git a/test/fixtures/config/theming/tasks/description/.gulp.json b/test/fixtures/config/theming/tasks/description/.gulp.json new file mode 100644 index 00000000..64cf05b0 --- /dev/null +++ b/test/fixtures/config/theming/tasks/description/.gulp.json @@ -0,0 +1,12 @@ +{ + "log": { + "msgs": { + "tasks": { + "description": "{FILE: {1}}" + } + }, + "theme": { + "FILE": "** {1} **" + } + } +} diff --git a/test/fixtures/config/theming/tasks/description/gulpfile.js b/test/fixtures/config/theming/tasks/description/gulpfile.js new file mode 100644 index 00000000..db73dd16 --- /dev/null +++ b/test/fixtures/config/theming/tasks/description/gulpfile.js @@ -0,0 +1,3 @@ +exports.default = function(done) { + done(); +} diff --git a/test/fixtures/config/theming/tasks/description/remove/.gulp.json b/test/fixtures/config/theming/tasks/description/remove/.gulp.json new file mode 100644 index 00000000..b2004178 --- /dev/null +++ b/test/fixtures/config/theming/tasks/description/remove/.gulp.json @@ -0,0 +1,9 @@ +{ + "log": { + "msgs": { + "tasks": { + "description": null + } + } + } +} diff --git a/test/fixtures/config/theming/tasks/description/remove/gulpfile.js b/test/fixtures/config/theming/tasks/description/remove/gulpfile.js new file mode 100644 index 00000000..db73dd16 --- /dev/null +++ b/test/fixtures/config/theming/tasks/description/remove/gulpfile.js @@ -0,0 +1,3 @@ +exports.default = function(done) { + done(); +} diff --git a/test/fixtures/config/theming/tasks/option/.gulp.js b/test/fixtures/config/theming/tasks/option/.gulp.js new file mode 100644 index 00000000..33eada33 --- /dev/null +++ b/test/fixtures/config/theming/tasks/option/.gulp.js @@ -0,0 +1,12 @@ +module.exports = { + log: { + msgs: { + tasks: { + option: '{1}{OptionName: {2}}{IF:{3}?{4}» {5}}', + } + }, + theme: { + OptionName: '**{1}**', + }, + }, +}; diff --git a/test/fixtures/config/theming/tasks/option/gulpfile.js b/test/fixtures/config/theming/tasks/option/gulpfile.js new file mode 100644 index 00000000..b61b53c3 --- /dev/null +++ b/test/fixtures/config/theming/tasks/option/gulpfile.js @@ -0,0 +1,27 @@ +const { series } = require('gulp'); + +function taskA(done) { + done(); +} +taskA.description = 'This is task A'; +taskA.flags = { + '--abc': 'is a flag for task A', +}; + +const taskB = function(done) { + done(); +} +taskB.description = 'This is task B'; +taskB.flags = { + '--def': 'is a flag for task B', +}; + +const defaults = series(taskA, taskB); +defaults.description = 'This is default task'; +defaults.flags = { + '--ghi': 'is a flag for default task', +}; + +exports.default = defaults; +exports.taskA = taskA; +exports.taskB = taskB; diff --git a/test/fixtures/config/theming/tasks/topTask/.gulp.js b/test/fixtures/config/theming/tasks/topTask/.gulp.js new file mode 100644 index 00000000..90c2b2a3 --- /dev/null +++ b/test/fixtures/config/theming/tasks/topTask/.gulp.js @@ -0,0 +1,12 @@ +module.exports = { + log: { + msgs: { + tasks: { + topTask: '{1}{TaskName: {2}}{IF:{3}?{4}{5}}', + } + }, + theme: { + TaskName: '**{1}**', + }, + }, +}; diff --git a/test/fixtures/config/theming/tasks/topTask/gulpfile.js b/test/fixtures/config/theming/tasks/topTask/gulpfile.js new file mode 100644 index 00000000..b61b53c3 --- /dev/null +++ b/test/fixtures/config/theming/tasks/topTask/gulpfile.js @@ -0,0 +1,27 @@ +const { series } = require('gulp'); + +function taskA(done) { + done(); +} +taskA.description = 'This is task A'; +taskA.flags = { + '--abc': 'is a flag for task A', +}; + +const taskB = function(done) { + done(); +} +taskB.description = 'This is task B'; +taskB.flags = { + '--def': 'is a flag for task B', +}; + +const defaults = series(taskA, taskB); +defaults.description = 'This is default task'; +defaults.flags = { + '--ghi': 'is a flag for default task', +}; + +exports.default = defaults; +exports.taskA = taskA; +exports.taskB = taskB; diff --git a/test/fixtures/config/theming/tasksJson/description/.gulp.json b/test/fixtures/config/theming/tasksJson/description/.gulp.json new file mode 100644 index 00000000..0a186d7f --- /dev/null +++ b/test/fixtures/config/theming/tasksJson/description/.gulp.json @@ -0,0 +1,12 @@ +{ + "log": { + "msgs": { + "tasksJson": { + "description": "{FILE: {1}}" + } + }, + "theme": { + "FILE": "** {1} **" + } + } +} diff --git a/test/fixtures/config/theming/tasksJson/description/gulpfile.js b/test/fixtures/config/theming/tasksJson/description/gulpfile.js new file mode 100644 index 00000000..db73dd16 --- /dev/null +++ b/test/fixtures/config/theming/tasksJson/description/gulpfile.js @@ -0,0 +1,3 @@ +exports.default = function(done) { + done(); +} diff --git a/test/fixtures/config/theming/warn/loaderFailure/.gulp.js b/test/fixtures/config/theming/warn/loaderFailure/.gulp.js new file mode 100644 index 00000000..816e2bdf --- /dev/null +++ b/test/fixtures/config/theming/warn/loaderFailure/.gulp.js @@ -0,0 +1,12 @@ +module.exports = { + log: { + msgs: { + warn: { + loaderFailure: '{TIMESTAMP}FAIL TO LOAD {ModuleName: {1}}', + }, + }, + theme: { + ModuleName: '**{1}**', + }, + }, +}; diff --git a/test/fixtures/config/theming/warn/loaderFailure/gulpfile.coffee b/test/fixtures/config/theming/warn/loaderFailure/gulpfile.coffee new file mode 100644 index 00000000..1f8b8541 --- /dev/null +++ b/test/fixtures/config/theming/warn/loaderFailure/gulpfile.coffee @@ -0,0 +1 @@ +console.log 'hello' diff --git a/test/fixtures/config/theming/warn/preloadFailure/.gulp.js b/test/fixtures/config/theming/warn/preloadFailure/.gulp.js new file mode 100644 index 00000000..ca3e42fe --- /dev/null +++ b/test/fixtures/config/theming/warn/preloadFailure/.gulp.js @@ -0,0 +1,12 @@ +module.exports = { + log: { + msgs: { + warn: { + preloadFailure: '{TIMESTAMP}FAILED TO PRELOAD {ModuleName: {1}}', + }, + }, + theme: { + ModuleName: '**{1}**', + }, + }, +}; diff --git a/test/fixtures/config/theming/warn/preloadFailure/gulpfile.js b/test/fixtures/config/theming/warn/preloadFailure/gulpfile.js new file mode 100644 index 00000000..db73dd16 --- /dev/null +++ b/test/fixtures/config/theming/warn/preloadFailure/gulpfile.js @@ -0,0 +1,3 @@ +exports.default = function(done) { + done(); +} diff --git a/test/fixtures/config/theming/warn/taskNotComplete/.gulp.js b/test/fixtures/config/theming/warn/taskNotComplete/.gulp.js new file mode 100644 index 00000000..38e5a949 --- /dev/null +++ b/test/fixtures/config/theming/warn/taskNotComplete/.gulp.js @@ -0,0 +1,12 @@ +module.exports = { + log: { + msgs: { + warn: { + taskNotComplete: '{TIMESTAMP}TASK {TaskName: {1}} DID NOT COMPLETE', + }, + }, + theme: { + TaskName: '**{1}**', + }, + }, +}; diff --git a/test/fixtures/config/theming/warn/taskNotComplete/gulpfile.js b/test/fixtures/config/theming/warn/taskNotComplete/gulpfile.js new file mode 100644 index 00000000..1e950f9a --- /dev/null +++ b/test/fixtures/config/theming/warn/taskNotComplete/gulpfile.js @@ -0,0 +1,3 @@ +exports.default = function(done) { + //done(); +} diff --git a/test/fixtures/errors/yarn/yarn.lock b/test/fixtures/errors/yarn/yarn.lock new file mode 100644 index 00000000..e69de29b diff --git a/test/fixtures/gulpfiles/.gulp.json b/test/fixtures/gulpfiles/.gulp.json index 65158fad..0eae6480 100644 --- a/test/fixtures/gulpfiles/.gulp.json +++ b/test/fixtures/gulpfiles/.gulp.json @@ -1,3 +1,12 @@ { - "description" : "gulp-cli/test/fixtures/gulpfiles" + "log": { + "msgs": { + "tasks": { + "description" : "gulp-cli/test/fixtures/gulpfiles" + }, + "tasksJson": { + "description" : "gulp-cli/test/fixtures/gulpfiles" + } + } + } } diff --git a/test/flags-help.js b/test/flags-help.js index b1947b41..3007e288 100644 --- a/test/flags-help.js +++ b/test/flags-help.js @@ -58,4 +58,15 @@ describe('flag: --help', function() { } }); + it('show error message and help if options are invalid', function(done) { + var opts = { cwd: baseDir }; + exec(gulp('-f'), opts, cb); + + function cb(err, stdout, stderr) { + expect(err).not.toBeNull(); + expect(stdout).toEqual(''); + expect(stderr).toEqual('Not enough arguments following: f\n' + outputText); + done(); + } + }); }); diff --git a/test/flags-tasks.js b/test/flags-tasks.js index 4a1c689f..5af06ba1 100644 --- a/test/flags-tasks.js +++ b/test/flags-tasks.js @@ -31,7 +31,7 @@ describe('flag: --tasks', function() { } }); - it('print the task list with description and flags', function(done) { + it('prints the task list with description and flags', function(done) { var opts = { cwd: baseDir }; exec(gulp( '--tasks', @@ -50,7 +50,7 @@ describe('flag: --tasks', function() { } }); - it('print the task list by gulp.task(s).unwrap and gulp.task(s)', function(done) { + it('prints the task list by gulp.task(s).unwrap and gulp.task(s)', function(done) { var opts = { cwd: baseDir }; exec(gulp( '--tasks', @@ -122,6 +122,24 @@ describe('flag: --tasks', function() { } }); + it('prints the top task only if negative tasks depth is specified', function(done) { + var opts = { cwd: baseDir }; + exec(gulp( + '--tasks', + '--gulpfile ./test/fixtures/gulpfiles/gulpfile-4.js', + '--tasks-depth -1' + ), opts, cb); + + function cb(err, stdout, stderr) { + expect(err).toBeNull(); + expect(stderr).toEqual(''); + var filepath = path.join(expectedDir, 'flags-tasks-depth1.txt'); + var expected = fs.readFileSync(filepath, 'utf-8'); + expect(sliceLines(stdout, 1)).toEqual(expected); + done(err); + } + }); + it('prints the task list with --depth flag', function(done) { var opts = { cwd: baseDir }; exec(gulp( diff --git a/test/lib/check-task-not-found.js b/test/lib/check-task-not-found.js new file mode 100644 index 00000000..932c753c --- /dev/null +++ b/test/lib/check-task-not-found.js @@ -0,0 +1,28 @@ +'use strict'; + +var expect = require('expect'); +var checkTaskNotFound = require('../../lib/versioned/^4.0.0/log/check-task-not-found'); + +describe('lib: checkTaskNotFound', function() { + + it('Should return target task and similar tasks if both are included in error message', function(done) { + var err = new Error('Task never defined: task2 - did you mean? task0, task1'); + expect(checkTaskNotFound(err)).toEqual({ + target: 'task2', + similar: 'task0, task1', + }); + done(); + }); + + it('Should return only target task if similar tasks is not included in error message', function(done) { + var err = new Error('Task never defined: task2'); + expect(checkTaskNotFound(err)).toEqual({ target: 'task2' }); + done(); + }); + + it('Should return undefined if error is other', function(done) { + var err = new Error('xxx'); + expect(checkTaskNotFound(err)).toBeUndefined(); + done(); + }); +}); diff --git a/test/lib/config-cli-flags.js b/test/lib/config-cli-flags.js index e70a0d92..d78e07a1 100644 --- a/test/lib/config-cli-flags.js +++ b/test/lib/config-cli-flags.js @@ -3,7 +3,7 @@ var expect = require('expect'); var mergeCliOpts = require('../../lib/shared/config/cli-flags'); -describe('lib: config/cli-flags', function() { +describe('lib: cli-flags', function() { it('Should copy only config props specified to cli flags', function(done) { var opts = {}; diff --git a/test/lib/format-hrtime.js b/test/lib/format-hrtime.js index 71eb9989..d520c3a1 100644 --- a/test/lib/format-hrtime.js +++ b/test/lib/format-hrtime.js @@ -3,7 +3,7 @@ var expect = require('expect'); var formatHrtime = require('../../lib/shared/log/format-hrtime'); -describe('format-hrtime', function() { +describe('lib: format-hrtime', function() { describe('should convert hrtime to string: unit is "h"', function() { it('should be no decimal part if integer part greater than 10', function(done) { expect(formatHrtime([36000, 100])).toEqual('10 h'); diff --git a/test/lib/merge-configs.js b/test/lib/merge-configs.js deleted file mode 100644 index 6d0a4bea..00000000 --- a/test/lib/merge-configs.js +++ /dev/null @@ -1,119 +0,0 @@ -'use strict'; - -var expect = require('expect'); -var path = require('path'); -var mergeConfigs = require('../../lib/shared/config/merge-configs'); - -var fixturesDir = path.join(__dirname, '../fixtures/config'); - -describe('lib: config/merge-configs', function() { - - it('Should get merged config when there is only project config', function(done) { - var config = { - project: { - description: 'description by .gulp.js in directory project', - }, - userHome: {}, - }; - var configFiles = { - project: path.join(fixturesDir, 'project/.gulp.js'), - userHome: undefined, - }; - var env = { - config: config, - configFiles: configFiles, - }; - - var cfg = mergeConfigs(env); - - expect(cfg).toEqual({ - description: 'description by .gulp.js in directory project', - }); - done(); - }); - - it('Should get merged config when there is only user-home config', function(done) { - var config = { - project: {}, - userHome: { - description: 'description by .gulp.js in directory user home', - }, - }; - var configFiles = { - project: undefined, - userHome: path.join(fixturesDir, 'user/home/.gulp.js'), - }; - var env = { - config: config, - configFiles: configFiles, - }; - - var cfg = mergeConfigs(env); - - expect(cfg).toEqual({ - description: 'description by .gulp.js in directory user home', - }); - done(); - }); - - it('Should get merged config when there are both project and user-home config', function(done) { - var config = { - project: { - description: 'description by .gulp.js in directory project', - flags: { - series: true, - }, - }, - userHome: { - description: 'description by .gulp.js in directory user home', - flags: { - silent: true, - }, - }, - }; - var configFiles = { - project: path.join(fixturesDir, 'project/gulp.js'), - userHome: path.join(fixturesDir, 'user/home/.gulp.js'), - }; - var env = { - config: config, - configFiles: configFiles, - }; - - var cfg = mergeConfigs(env); - - expect(cfg).toEqual({ - description: 'description by .gulp.js in directory project', - flags: { - series: true, - silent: true, - }, - }); - done(); - }); - - it('Should convert a value of `flags.gulpfile` to absolute path', function(done) { - var config = { - project: { - flags: { gulpfile: './is/here/mygulpfile.js' }, - }, - }; - var configFiles = { - project: path.join(fixturesDir, 'flags/gulpfile/.gulp.json'), - }; - var env = { - config: config, - configFiles: configFiles, - }; - - var cfg = mergeConfigs(env); - - expect(cfg).toEqual({ - flags: { - gulpfile: path.join(fixturesDir, 'flags/gulpfile/is/here/mygulpfile.js'), - }, - }); - done(); - }); - -}); diff --git a/test/lib/config-env-flags.js b/test/lib/override-env-config.js similarity index 55% rename from test/lib/config-env-flags.js rename to test/lib/override-env-config.js index d8062c08..d65324f9 100644 --- a/test/lib/config-env-flags.js +++ b/test/lib/override-env-config.js @@ -1,30 +1,52 @@ 'use strict'; var expect = require('expect'); -var overrideEnvFlags = require('../../lib/shared/config/env-flags'); +var copyProps = require('copy-props'); +var overrideEnvConfig = require('../../lib/shared/config/env-config'); +var theme = require('../../lib/shared/log/theme'); +var msgs = require('../../lib/shared/log/messages'); -describe('lib: config/env-flags', function() { +describe('lib: env-config', function() { + + var originalTheme = copyProps(theme, {}); + var originalMsgs = copyProps(msgs, {}); + + after(function() { + var keys = Object.keys(theme); + keys.forEach(function(key) { + delete theme[key]; + }); + copyProps(originalTheme, theme); + + keys = Object.keys(msgs); + keys.forEach(function(key) { + delete msgs[key]; + }); + copyProps(originalMsgs, msgs); + }); it('Should copy only config props specified to env flags', function(done) { var env = {}; var config = { - description: 'DESCRIPTION.', flags: { silent: true, gulpfile: '/path/to/gulpfile', }, }; - var result = overrideEnvFlags(env, config, {}); + var result = overrideEnvConfig(env, config, {}); expect(result).toEqual({ configPath: '/path/to/gulpfile', configBase: '/path/to', config: { - description: 'DESCRIPTION.', flags: { silent: true, }, + log: { + theme: theme, + msgs: msgs, + }, }, }); expect(result).toBe(env); @@ -44,19 +66,38 @@ describe('lib: config/env-flags', function() { }; var config = { - description: 'DESCRIPTION.', flags: { silent: false, gulpfile: '/path/to/gulpfile', preload: ['a', 'b'], }, + log: { + theme: { + INFO: '{black: {1}}', + WARN: '{bgYellow: {1}}', + ERROR: '{bgRed: {1}}', + }, + msgs: { + tasks: { + description: 'DESCRIPTION', + }, + }, + }, }; + var resultTheme = copyProps(theme, {}); + resultTheme.INFO = config.log.theme.INFO; + resultTheme.WARN = config.log.theme.WARN; + resultTheme.ERROR = config.log.theme.ERROR; + + var resultMsgs = copyProps(msgs, {}); + resultMsgs.tasks.description = config.log.msgs.tasks.description; + var opts = { gulpfile: env.configPath, }; - var result = overrideEnvFlags(env, config, opts); + var result = overrideEnvConfig(env, config, opts); expect(result).toEqual({ cwd: '/path/to/cwd', preload: ['preload', 'a', 'b'], @@ -67,11 +108,14 @@ describe('lib: config/env-flags', function() { modulePackage: { name: 'modulePackage' }, configFiles: { aaa: {} }, config: { - description: "DESCRIPTION.", flags: { gulpfile: "/path/of/config/path", silent: false, }, + log: { + theme: resultTheme, + msgs: resultMsgs, + }, }, }); expect(result).toBe(env); @@ -92,7 +136,7 @@ describe('lib: config/env-flags', function() { var config = {}; - var result = overrideEnvFlags(env, config, {}); + var result = overrideEnvConfig(env, config, {}); expect(result).toEqual({ cwd: '/path/to/cwd', preload: 'preload', @@ -104,6 +148,32 @@ describe('lib: config/env-flags', function() { configFiles: { aaa: {} }, config: { flags: {}, + log: { + theme: theme, + msgs: msgs, + }, + }, + }); + expect(result).toBe(env); + done(); + }); + + it('Should not cause error if config.flags and config.log is empty', function(done) { + var env = {}; + + var config = { + flags: {}, + log: {}, + }; + + var result = overrideEnvConfig(env, config, {}); + expect(result).toEqual({ + config: { + flags: {}, + log: { + theme: theme, + msgs: msgs, + }, }, }); expect(result).toBe(env); diff --git a/test/lib/theme.js b/test/lib/theme.js new file mode 100644 index 00000000..7329a137 --- /dev/null +++ b/test/lib/theme.js @@ -0,0 +1,103 @@ +'use strict'; + +var expect = require('expect'); +var format = require('theming-log').format; +var theme = require('../../lib/shared/log/theme'); + +describe('lib: theme', function() { + + it('styles', function(done) { + if (process.env.CI) { + this.skip(); + return; + } + + expect(theme.reset('hello', 'world')).toEqual('\x1B[0mhello world\x1B[0m'); + expect(theme.bold('hello', 'world')).toEqual('\x1B[1mhello world\x1B[22m'); + expect(theme.dim('hello', 'world')).toEqual('\x1B[2mhello world\x1B[22m'); + expect(theme.italic('hello', 'world')).toEqual('\x1B[3mhello world\x1B[23m'); + expect(theme.underline('hello', 'world')).toEqual('\x1B[4mhello world\x1B[24m'); + expect(theme.inverse('hello', 'world')).toEqual('\x1B[7mhello world\x1B[27m'); + expect(theme.hidden('hello', 'world')).toEqual('\x1B[8mhello world\x1B[28m'); + expect(theme.strikethrough('hello', 'world')).toEqual('\x1B[9mhello world\x1B[29m'); + expect(theme.visible('hello', 'world')).toEqual('hello world'); + + expect(theme.black('hello', 'world')).toEqual('\x1B[30mhello world\x1B[39m'); + expect(theme.red('hello', 'world')).toEqual('\x1B[31mhello world\x1B[39m'); + expect(theme.green('hello', 'world')).toEqual('\x1B[32mhello world\x1B[39m'); + expect(theme.yellow('hello', 'world')).toEqual('\x1B[33mhello world\x1B[39m'); + expect(theme.blue('hello', 'world')).toEqual('\x1B[34mhello world\x1B[39m'); + expect(theme.magenta('hello', 'world')).toEqual('\x1B[35mhello world\x1B[39m'); + expect(theme.cyan('hello', 'world')).toEqual('\x1B[36mhello world\x1B[39m'); + expect(theme.white('hello', 'world')).toEqual('\x1B[37mhello world\x1B[39m'); + expect(theme.blackBright('hello', 'world')).toEqual('\x1B[90mhello world\x1B[39m'); + expect(theme.gray('hello', 'world')).toEqual('\x1B[90mhello world\x1B[39m'); + expect(theme.grey('hello', 'world')).toEqual('\x1B[90mhello world\x1B[39m'); + expect(theme.redBright('hello', 'world')).toEqual('\x1B[91mhello world\x1B[39m'); + expect(theme.greenBright('hello', 'world')).toEqual('\x1B[92mhello world\x1B[39m'); + expect(theme.yellowBright('hello', 'world')).toEqual('\x1B[93mhello world\x1B[39m'); + expect(theme.blueBright('hello', 'world')).toEqual('\x1B[94mhello world\x1B[39m'); + expect(theme.magentaBright('hello', 'world')).toEqual('\x1B[95mhello world\x1B[39m'); + expect(theme.cyanBright('hello', 'world')).toEqual('\x1B[96mhello world\x1B[39m'); + expect(theme.whiteBright('hello', 'world')).toEqual('\x1B[97mhello world\x1B[39m'); + + expect(theme.bgBlack('hello', 'world')).toEqual('\x1B[40mhello world\x1B[49m'); + expect(theme.bgRed('hello', 'world')).toEqual('\x1B[41mhello world\x1B[49m'); + expect(theme.bgGreen('hello', 'world')).toEqual('\x1B[42mhello world\x1B[49m'); + expect(theme.bgYellow('hello', 'world')).toEqual('\x1B[43mhello world\x1B[49m'); + expect(theme.bgBlue('hello', 'world')).toEqual('\x1B[44mhello world\x1B[49m'); + expect(theme.bgMagenta('hello', 'world')).toEqual('\x1B[45mhello world\x1B[49m'); + expect(theme.bgCyan('hello', 'world')).toEqual('\x1B[46mhello world\x1B[49m'); + expect(theme.bgWhite('hello', 'world')).toEqual('\x1B[47mhello world\x1B[49m'); + expect(theme.bgBlackBright('hello', 'world')).toEqual('\x1B[100mhello world\x1B[49m'); + expect(theme.bgGray('hello', 'world')).toEqual('\x1B[100mhello world\x1B[49m'); + expect(theme.bgGrey('hello', 'world')).toEqual('\x1B[100mhello world\x1B[49m'); + expect(theme.bgRedBright('hello', 'world')).toEqual('\x1B[101mhello world\x1B[49m'); + expect(theme.bgGreenBright('hello', 'world')).toEqual('\x1B[102mhello world\x1B[49m'); + expect(theme.bgYellowBright('hello', 'world')).toEqual('\x1B[103mhello world\x1B[49m'); + expect(theme.bgBlueBright('hello', 'world')).toEqual('\x1B[104mhello world\x1B[49m'); + expect(theme.bgMagentaBright('hello', 'world')).toEqual('\x1B[105mhello world\x1B[49m'); + expect(theme.bgCyanBright('hello', 'world')).toEqual('\x1B[106mhello world\x1B[49m'); + expect(theme.bgWhiteBright('hello', 'world')).toEqual('\x1B[107mhello world\x1B[49m'); + + done(); + }); + + it('templates', function(done) { + if (process.env.CI) { + this.skip(); + return; + } + + /* eslint new-cap: 0 */ + expect(theme.NOW('HH:mm')).toMatch(/^\d{2}:\d{2}$/); + + expect(format(theme, '{HELP.DESC: {1}}', 'hello')).toEqual('\x1B[90mhello\x1B[39m'); + expect(format(theme, '{DESC: {1}}', 'hello')).toEqual('hello'); + expect(format(theme, '{PATH: {1}}', 'hello')).toEqual('\x1B[35mhello\x1B[39m'); + expect(format(theme, '{PID: {1}}', 'hello')).toEqual('\x1B[35mhello\x1B[39m'); + expect(format(theme, '{MODULE: {1}}', 'hello')).toEqual('\x1B[35mhello\x1B[39m'); + expect(format(theme, '{VERSION: {1}}', 'hello')).toEqual('hello'); + expect(format(theme, '{TITLE: {1}}', 'hello')).toEqual('\x1B[1mhello\x1B[22m'); + expect(format(theme, '{TASK: {1}}', 'hello')).toEqual('\x1B[36mhello\x1B[39m'); + expect(format(theme, '{OPTION: {1}}', 'hello')).toEqual('\x1B[34mhello\x1B[39m'); + expect(format(theme, '{DURATION: {1}}', 'hello')).toEqual('\x1B[35mhello\x1B[39m'); + + expect(format(theme, '{TASKS.BRANCH: {1}}', 'hello')).toEqual('hello'); + expect(format(theme, '{TASKS.NAME: {1}}', 'hello')).toEqual('\x1B[36mhello\x1B[39m'); + expect(format(theme, '{TASKS.OPTION: {1}}', 'hello')).toEqual('\x1B[34mhello\x1B[39m'); + expect(format(theme, '{TASKS.DESC: {1}}', 'hello')).toEqual('hello'); + expect(format(theme, '{TASKS.CHILD: {1}}', 'hello')).toEqual('hello'); + + expect(format(theme, '{INFO: {1}}', 'hello')).toEqual('hello'); + expect(format(theme, '{WARN: {1}}', 'hello')).toEqual('\x1B[33mhello\x1B[39m'); + expect(format(theme, '{ERROR: {1}}', 'hello')).toEqual('\x1B[31mhello\x1B[39m'); + + /* eslint no-control-regex: 0 */ + expect(format(theme, '{TIMESTAMP: {1}}', 'HH:mm:ss')).toMatch(/^\[\x1B\[90m\d{2}:\d{2}:\d{2}\x1B\[39m\] $/); + + expect(format(theme, '{IF: {1}?{2}}', true, 'hello')).toEqual('hello'); + expect(format(theme, '{IF: {1}?{2}}', false, 'hello')).toEqual(''); + done(); + }); +}); diff --git a/test/lib/timestamp.js b/test/lib/timestamp.js new file mode 100644 index 00000000..ae827ecd --- /dev/null +++ b/test/lib/timestamp.js @@ -0,0 +1,57 @@ +'use strict'; + +var expect = require('expect'); +var timestamp = require('../../lib/shared/log/timestamp'); + +describe('lib: timestamp', function() { + + it('should output each element', function(done) { + var before = new Date(); + + var year = timestamp('YYYY'); + var month = timestamp('MM'); + var date = timestamp('DD'); + var hours = timestamp('HH'); + var minutes = timestamp('mm'); + var seconds = timestamp('ss'); + var millis = timestamp('SSS'); + + var after = new Date(); + + expect(year).toHaveLength(4); + expect(Number(year)).toBeGreaterThanOrEqual(before.getFullYear()); + expect(Number(year)).toBeLessThanOrEqual(after.getFullYear()); + + expect(month).toHaveLength(2); + expect(Number(month)).toBeGreaterThanOrEqual(before.getMonth() + 1); + expect(Number(month)).toBeLessThanOrEqual(after.getMonth() + 1); + + expect(date).toHaveLength(2); + expect(Number(date)).toBeGreaterThanOrEqual(before.getDate()); + expect(Number(date)).toBeLessThanOrEqual(after.getDate()); + + expect(hours).toHaveLength(2); + expect(Number(hours)).toBeGreaterThanOrEqual(before.getHours()); + expect(Number(hours)).toBeLessThanOrEqual(after.getHours()); + + expect(minutes).toHaveLength(2); + expect(Number(minutes)).toBeGreaterThanOrEqual(before.getMinutes()); + expect(Number(minutes)).toBeLessThanOrEqual(after.getMinutes()); + + expect(seconds).toHaveLength(2); + expect(Number(seconds)).toBeGreaterThanOrEqual(before.getSeconds()); + expect(Number(seconds)).toBeLessThanOrEqual(after.getSeconds()); + + expect(millis).toHaveLength(3); + expect(Number(millis)).toBeGreaterThanOrEqual(before.getMilliseconds()); + expect(Number(millis)).toBeLessThanOrEqual(after.getMilliseconds()); + + done(); + }); + + it('should output in specified format', function(done) { + expect(timestamp('YYYY/MM/DD HH:mm:ss')).toMatch(/^\d{4}\/\d{2}\/\d{2} \d{2}:\d{2}:\d{2}$/); + expect(timestamp('YYYY-MM-DDTHH:mm:ss.SSSZ')).toMatch(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z$/); + done(); + }); +});