From dcb0cf7af31492cca67f22016de41909c44223d3 Mon Sep 17 00:00:00 2001 From: Alexander Kuznetsov Date: Mon, 9 Nov 2015 13:33:32 +0300 Subject: [PATCH 1/3] Configurable stats colors Default colors may not look good with some terminal color settings, so this patch allows to setup stats colors explicitly: ``` var config = { stats: { colors: { yellow: '\u001b[33m', green: '\u001b[32m' } } } ``` `colors: true` will use default colors. --- lib/Stats.js | 287 ++++++++++++++++++++++++--------------------------- 1 file changed, 136 insertions(+), 151 deletions(-) diff --git a/lib/Stats.js b/lib/Stats.js index 9e08124a7..e15a9cdda 100644 --- a/lib/Stats.js +++ b/lib/Stats.js @@ -312,45 +312,30 @@ Stats.prototype.toString = function toString(options) { Stats.jsonToString = function jsonToString(obj, useColors) { var buf = []; - function normal(str) { - buf.push(str); - } + var defaultColors = { + bold: "\u001b[1m", + yellow: "\u001b[1m\u001b[33m", + red: "\u001b[1m\u001b[31m", + green: "\u001b[1m\u001b[32m", + cyan: "\u001b[1m\u001b[36m", + magenta: "\u001b[1m\u001b[35m" + }; - function bold(str) { - if(useColors) buf.push("\u001b[1m"); - buf.push(str); - if(useColors) buf.push("\u001b[22m"); - } - - function yellow(str) { - if(useColors) buf.push("\u001b[1m\u001b[33m"); - buf.push(str); - if(useColors) buf.push("\u001b[39m\u001b[22m"); - } - - function red(str) { - if(useColors) buf.push("\u001b[1m\u001b[31m"); - buf.push(str); - if(useColors) buf.push("\u001b[39m\u001b[22m"); - } - - function green(str) { - if(useColors) buf.push("\u001b[1m\u001b[32m"); - buf.push(str); - if(useColors) buf.push("\u001b[39m\u001b[22m"); - } - - function cyan(str) { - if(useColors) buf.push("\u001b[1m\u001b[36m"); - buf.push(str); - if(useColors) buf.push("\u001b[39m\u001b[22m"); - } - - function magenta(str) { - if(useColors) buf.push("\u001b[1m\u001b[35m"); - buf.push(str); - if(useColors) buf.push("\u001b[39m\u001b[22m"); - } + var colors = Object.keys(defaultColors).reduce(function(obj, color) { + obj[color] = function(str) { + if(useColors) { + buf.push( + (useColors === true || useColors[color] === undefined) ? + defaultColors[color] : useColors[color] + ); + } + buf.push(str); + if(useColors) { + buf.push("\u001b[39m\u001b[22m"); + } + }; + return obj; + }, { normal: function (str) { buf.push(str); } }); function coloredTime(time) { var times = [800, 400, 200, 100]; @@ -358,15 +343,15 @@ Stats.jsonToString = function jsonToString(obj, useColors) { times = [obj.time / 2, obj.time / 4, obj.time / 8, obj.time / 16]; } if(time < times[3]) - normal(time + "ms"); + colors.normal(time + "ms"); else if(time < times[2]) - bold(time + "ms"); + colors.bold(time + "ms"); else if(time < times[1]) - green(time + "ms"); + colors.green(time + "ms"); else if(time < times[0]) - yellow(time + "ms"); + colors.yellow(time + "ms"); else - red(time + "ms"); + colors.red(time + "ms"); } function newline() { @@ -389,17 +374,17 @@ Stats.jsonToString = function jsonToString(obj, useColors) { } for(var row = 0; row < rows; row++) { for(var col = 0; col < cols; col++) { - var format = row === 0 ? bold : formats[col]; + var format = row === 0 ? colors.bold : formats[col]; var value = array[row][col] + ""; var l = value.length; if(align[col] === "l") format(value); for(; l < colSizes[col] && col !== cols - 1; l++) - normal(" "); + colors.normal(" "); if(align[col] === "r") format(value); if(col + 1 < cols) - normal(splitter || " "); + colors.normal(splitter || " "); } newline(); } @@ -416,24 +401,24 @@ Stats.jsonToString = function jsonToString(obj, useColors) { } if(obj.hash) { - normal("Hash: "); - bold(obj.hash); + colors.normal("Hash: "); + colors.bold(obj.hash); newline(); } if(obj.version) { - normal("Version: webpack "); - bold(obj.version); + colors.normal("Version: webpack "); + colors.bold(obj.version); newline(); } if(typeof obj.time === "number") { - normal("Time: "); - bold(obj.time); - normal("ms"); + colors.normal("Time: "); + colors.bold(obj.time); + colors.normal("ms"); newline(); } if(obj.publicPath) { - normal("PublicPath: "); - bold(obj.publicPath); + colors.normal("PublicPath: "); + colors.bold(obj.publicPath); newline(); } if(obj.assets && obj.assets.length > 0) { @@ -449,7 +434,7 @@ Stats.jsonToString = function jsonToString(obj, useColors) { asset.chunkNames.join(", ") ]); }); - table(t, [green, normal, bold, green, normal], "rrrll"); + table(t, [colors.green, colors.normal, colors.bold, colors.green, colors.normal], "rrrll"); } var modulesByIdentifier = {}; if(obj.modules) { @@ -468,39 +453,39 @@ Stats.jsonToString = function jsonToString(obj, useColors) { function processProfile(module) { if(module.profile) { - normal(" "); + colors.normal(" "); var sum = 0, allowSum = true; var path = []; var current = module; while(current.issuer) { if(!modulesByIdentifier["$" + current.issuer]) { - normal(" ... ->"); + colors.normal(" ... ->"); allowSum = false; break; } path.unshift(current = modulesByIdentifier["$" + current.issuer]); } path.forEach(function(module) { - normal(" ["); - normal(module.id); - normal("] "); + colors.normal(" ["); + colors.normal(module.id); + colors.normal("] "); if(module.profile) { var time = (module.profile.factory || 0) + (module.profile.building || 0); coloredTime(time); sum += time; - normal(" "); + colors.normal(" "); } - normal("->"); + colors.normal("->"); }); Object.keys(module.profile).forEach(function(key) { - normal(" " + key + ":"); + colors.normal(" " + key + ":"); var time = module.profile[key]; coloredTime(time); sum += time; }); if(allowSum) { - normal(" = "); + colors.normal(" = "); coloredTime(sum); } newline(); @@ -508,82 +493,82 @@ Stats.jsonToString = function jsonToString(obj, useColors) { } function processModuleAttributes(module) { - normal(" "); - normal(formatSize(module.size)); + colors.normal(" "); + colors.normal(formatSize(module.size)); if(module.chunks) { module.chunks.forEach(function(chunk) { - normal(" {"); - yellow(chunk); - normal("}"); + colors.normal(" {"); + colors.yellow(chunk); + colors.normal("}"); }); } if(!module.cacheable) { - red(" [not cacheable]"); + colors.red(" [not cacheable]"); } if(module.optional) { - yellow(" [optional]"); + colors.yellow(" [optional]"); } if(module.built) { - green(" [built]"); + colors.green(" [built]"); } if(module.prefetched) { - magenta(" [prefetched]"); + colors.magenta(" [prefetched]"); } if(module.failed) - red(" [failed]"); + colors.red(" [failed]"); if(module.warnings) - yellow(" [" + module.warnings + " warning" + (module.warnings === 1 ? "" : "s") + "]"); + colors.yellow(" [" + module.warnings + " warning" + (module.warnings === 1 ? "" : "s") + "]"); if(module.errors) - red(" [" + module.errors + " error" + (module.errors === 1 ? "" : "s") + "]"); + colors.red(" [" + module.errors + " error" + (module.errors === 1 ? "" : "s") + "]"); } if(obj.chunks) { obj.chunks.forEach(function(chunk) { - normal("chunk "); - if(chunk.id < 1000) normal(" "); - if(chunk.id < 100) normal(" "); - if(chunk.id < 10) normal(" "); - normal("{"); - yellow(chunk.id); - normal("} "); - green(chunk.files.join(", ")); + colors.normal("chunk "); + if(chunk.id < 1000) colors.normal(" "); + if(chunk.id < 100) colors.normal(" "); + if(chunk.id < 10) colors.normal(" "); + colors.normal("{"); + colors.yellow(chunk.id); + colors.normal("} "); + colors.green(chunk.files.join(", ")); if(chunk.names && chunk.names.length > 0) { - normal(" ("); - normal(chunk.names.join(", ")); - normal(")"); + colors.normal(" ("); + colors.normal(chunk.names.join(", ")); + colors.normal(")"); } - normal(" "); - normal(formatSize(chunk.size)); + colors.normal(" "); + colors.normal(formatSize(chunk.size)); chunk.parents.forEach(function(id) { - normal(" {"); - yellow(id); - normal("}"); + colors.normal(" {"); + colors.yellow(id); + colors.normal("}"); }); if(chunk.rendered) { - green(" [rendered]"); + colors.green(" [rendered]"); } newline(); if(chunk.origins) { chunk.origins.forEach(function(origin) { - normal(" > "); + colors.normal(" > "); if(origin.reasons && origin.reasons.length) { - yellow(origin.reasons.join(" ")); - normal(" "); + colors.yellow(origin.reasons.join(" ")); + colors.normal(" "); } if(origin.name) { - normal(origin.name); - normal(" "); + colors.normal(origin.name); + colors.normal(" "); } if(origin.module) { - normal("["); - normal(origin.moduleId); - normal("] "); + colors.normal("["); + colors.normal(origin.moduleId); + colors.normal("] "); var module = modulesByIdentifier["$" + origin.module]; if(module) { - bold(module.name); - normal(" "); + colors.bold(module.name); + colors.normal(" "); } if(origin.loc) { - normal(origin.loc); + colors.normal(origin.loc); } } newline(); @@ -591,30 +576,30 @@ Stats.jsonToString = function jsonToString(obj, useColors) { } if(chunk.modules) { chunk.modules.forEach(function(module) { - normal(" "); - if(module.id < 1000) normal(" "); - if(module.id < 100) normal(" "); - if(module.id < 10) normal(" "); - normal("["); - normal(module.id); - normal("] "); - bold(module.name); + colors.normal(" "); + if(module.id < 1000) colors.normal(" "); + if(module.id < 100) colors.normal(" "); + if(module.id < 10) colors.normal(" "); + colors.normal("["); + colors.normal(module.id); + colors.normal("] "); + colors.bold(module.name); processModuleAttributes(module); newline(); if(module.reasons) { module.reasons.forEach(function(reason) { - normal(" "); - normal(reason.type); - normal(" "); - cyan(reason.userRequest); - if(reason.templateModules) cyan(reason.templateModules.join(" ")); - normal(" ["); - normal(reason.moduleId); - normal("] "); - magenta(reason.module); + colors.normal(" "); + colors.normal(reason.type); + colors.normal(" "); + colors.cyan(reason.userRequest); + if(reason.templateModules) colors.cyan(reason.templateModules.join(" ")); + colors.normal(" ["); + colors.normal(reason.moduleId); + colors.normal("] "); + colors.magenta(reason.module); if(reason.loc) { - normal(" "); - normal(reason.loc); + colors.normal(" "); + colors.normal(reason.loc); } newline(); }); @@ -622,7 +607,7 @@ Stats.jsonToString = function jsonToString(obj, useColors) { processProfile(module); }); if(chunk.filteredModules > 0) { - normal(" + " + chunk.filteredModules + " hidden modules"); + colors.normal(" + " + chunk.filteredModules + " hidden modules"); newline(); } } @@ -630,29 +615,29 @@ Stats.jsonToString = function jsonToString(obj, useColors) { } if(obj.modules) { obj.modules.forEach(function(module) { - if(module.id < 1000) normal(" "); - if(module.id < 100) normal(" "); - if(module.id < 10) normal(" "); - normal("["); - normal(module.id); - normal("] "); - bold(module.name || module.identifier); + if(module.id < 1000) colors.normal(" "); + if(module.id < 100) colors.normal(" "); + if(module.id < 10) colors.normal(" "); + colors.normal("["); + colors.normal(module.id); + colors.normal("] "); + colors.bold(module.name || module.identifier); processModuleAttributes(module); newline(); if(module.reasons) { module.reasons.forEach(function(reason) { - normal(" "); - normal(reason.type); - normal(" "); - cyan(reason.userRequest); - if(reason.templateModules) cyan(reason.templateModules.join(" ")); - normal(" ["); - normal(reason.moduleId); - normal("] "); - magenta(reason.module); + colors.normal(" "); + colors.normal(reason.type); + colors.normal(" "); + colors.cyan(reason.userRequest); + if(reason.templateModules) colors.cyan(reason.templateModules.join(" ")); + colors.normal(" ["); + colors.normal(reason.moduleId); + colors.normal("] "); + colors.magenta(reason.module); if(reason.loc) { - normal(" "); - normal(reason.loc); + colors.normal(" "); + colors.normal(reason.loc); } newline(); }); @@ -660,32 +645,32 @@ Stats.jsonToString = function jsonToString(obj, useColors) { processProfile(module); }); if(obj.filteredModules > 0) { - normal(" + " + obj.filteredModules + " hidden modules"); + colors.normal(" + " + obj.filteredModules + " hidden modules"); newline(); } } if(obj._showWarnings && obj.warnings) { obj.warnings.forEach(function(warning) { newline(); - yellow("WARNING in " + warning); + colors.yellow("WARNING in " + warning); newline(); }); } if(obj._showErrors && obj.errors) { obj.errors.forEach(function(error) { newline(); - red("ERROR in " + error); + colors.red("ERROR in " + error); newline(); }); } if(obj.children) { obj.children.forEach(function(child) { if(child.name) { - normal("Child "); - bold(child.name); - normal(":"); + colors.normal("Child "); + colors.bold(child.name); + colors.normal(":"); } else { - normal("Child"); + colors.normal("Child"); } newline(); buf.push(" "); @@ -694,7 +679,7 @@ Stats.jsonToString = function jsonToString(obj, useColors) { }); } if(obj.needAdditionalPass) { - yellow("Compilation needs an additional pass and will compile again."); + colors.yellow("Compilation needs an additional pass and will compile again."); } while(buf[buf.length - 1] === "\n") buf.pop(); From 33356f65ba78ceb277f2375cccaf78b72d0414e7 Mon Sep 17 00:00:00 2001 From: Kuzya Date: Sat, 14 Nov 2015 01:05:20 +0300 Subject: [PATCH 2/3] fix code styling to pass tests --- lib/Stats.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/Stats.js b/lib/Stats.js index e15a9cdda..35f70e44b 100644 --- a/lib/Stats.js +++ b/lib/Stats.js @@ -335,7 +335,11 @@ Stats.jsonToString = function jsonToString(obj, useColors) { } }; return obj; - }, { normal: function (str) { buf.push(str); } }); + }, { + normal: function(str) { + buf.push(str); + } + }); function coloredTime(time) { var times = [800, 400, 200, 100]; From 46ebe3dbbd5f7f3906f9de88ccbc224cc45dd6f1 Mon Sep 17 00:00:00 2001 From: Kuzya Date: Sat, 14 Nov 2015 16:08:04 +0300 Subject: [PATCH 3/3] added test cases for colored output --- test/Stats.test.js | 21 ++++++++++++++++--- test/statsCases/color-disabled/expected.txt | 6 ++++++ test/statsCases/color-disabled/index.js | 0 .../color-disabled/webpack.config.js | 6 ++++++ .../color-enabled-custom/expected.txt | 6 ++++++ test/statsCases/color-enabled-custom/index.js | 0 .../color-enabled-custom/webpack.config.js | 9 ++++++++ test/statsCases/color-enabled/expected.txt | 6 ++++++ test/statsCases/color-enabled/index.js | 0 .../color-enabled/webpack.config.js | 6 ++++++ 10 files changed, 57 insertions(+), 3 deletions(-) create mode 100644 test/statsCases/color-disabled/expected.txt create mode 100644 test/statsCases/color-disabled/index.js create mode 100644 test/statsCases/color-disabled/webpack.config.js create mode 100644 test/statsCases/color-enabled-custom/expected.txt create mode 100644 test/statsCases/color-enabled-custom/index.js create mode 100644 test/statsCases/color-enabled-custom/webpack.config.js create mode 100644 test/statsCases/color-enabled/expected.txt create mode 100644 test/statsCases/color-enabled/index.js create mode 100644 test/statsCases/color-enabled/webpack.config.js diff --git a/test/Stats.test.js b/test/Stats.test.js index 9e76b83ec..150bd0905 100644 --- a/test/Stats.test.js +++ b/test/Stats.test.js @@ -63,17 +63,32 @@ describe("Stats", function() { var toStringOptions = { colors: false }; + var hasColorSetting = false; + if(typeof options.stats !== "undefined") { toStringOptions = options.stats; + + hasColorSetting = typeof options.stats.colors !== "undefined"; } var actual = stats.toString(toStringOptions); (typeof actual).should.be.eql("string"); - actual = - actual.replace(/\u001b\[[0-9;]*m/g, "") + if(!hasColorSetting) { + actual = actual + .replace(/\u001b\[[0-9;]*m/g, "") + .replace(/[0-9]+(\s?ms)/g, "X$1"); + } else { + actual = actual + .replace(/\u001b\[1m\u001b\[([0-9;]*)m/g, "") + .replace(/\u001b\[1m/g, "") + .replace(/\u001b\[39m\u001b\[22m/g, "") + .replace(/\u001b\[([0-9;]*)m/g, "") + .replace(/[0-9]+(<\/CLR>)?(\s?ms)/g, "X$1$2"); + } + + actual = actual .replace(/\r\n?/g, "\n") .replace(/[\t ]*Version:.+\n/g, "") - .replace(/[0-9]+(\s?ms)/g, "X$1") .replace(path.join(base, testName), "Xdir/" + testName); var expected = fs.readFileSync(path.join(base, testName, "expected.txt"), "utf-8").replace(/\r/g, ""); if(actual !== expected) { diff --git a/test/statsCases/color-disabled/expected.txt b/test/statsCases/color-disabled/expected.txt new file mode 100644 index 000000000..4d2b2bd33 --- /dev/null +++ b/test/statsCases/color-disabled/expected.txt @@ -0,0 +1,6 @@ +Hash: 976ca41fdcf0493c675a +Time: Xms + Asset Size Chunks Chunk Names +main.js 1.53 kB 0 [emitted] main +chunk {0} main.js (main) 0 bytes [rendered] + [0] (webpack)/test/statsCases/color-disabled/index.js 0 bytes {0} [built] \ No newline at end of file diff --git a/test/statsCases/color-disabled/index.js b/test/statsCases/color-disabled/index.js new file mode 100644 index 000000000..e69de29bb diff --git a/test/statsCases/color-disabled/webpack.config.js b/test/statsCases/color-disabled/webpack.config.js new file mode 100644 index 000000000..cf2021dda --- /dev/null +++ b/test/statsCases/color-disabled/webpack.config.js @@ -0,0 +1,6 @@ +module.exports = { + entry: "./index", + stats: { + colors: false + } +}; diff --git a/test/statsCases/color-enabled-custom/expected.txt b/test/statsCases/color-enabled-custom/expected.txt new file mode 100644 index 000000000..3be618879 --- /dev/null +++ b/test/statsCases/color-enabled-custom/expected.txt @@ -0,0 +1,6 @@ +Hash: 976ca41fdcf0493c675a +Time: Xms + Asset Size Chunks Chunk Names +main.js 1.53 kB 0 [emitted] main +chunk {0} main.js (main) 0 bytes [rendered] + [0] (webpack)/test/statsCases/color-enabled-custom/index.js 0 bytes {0} [built] \ No newline at end of file diff --git a/test/statsCases/color-enabled-custom/index.js b/test/statsCases/color-enabled-custom/index.js new file mode 100644 index 000000000..e69de29bb diff --git a/test/statsCases/color-enabled-custom/webpack.config.js b/test/statsCases/color-enabled-custom/webpack.config.js new file mode 100644 index 000000000..e05b3b1f2 --- /dev/null +++ b/test/statsCases/color-enabled-custom/webpack.config.js @@ -0,0 +1,9 @@ +module.exports = { + entry: "./index", + stats: { + colors: { + yellow: '\u001b[33m', + green: '\u001b[32m' + } + } +}; diff --git a/test/statsCases/color-enabled/expected.txt b/test/statsCases/color-enabled/expected.txt new file mode 100644 index 000000000..9d6dc6412 --- /dev/null +++ b/test/statsCases/color-enabled/expected.txt @@ -0,0 +1,6 @@ +Hash: 976ca41fdcf0493c675a +Time: Xms + Asset Size Chunks Chunk Names +main.js 1.53 kB 0 [emitted] main +chunk {0} main.js (main) 0 bytes [rendered] + [0] (webpack)/test/statsCases/color-enabled/index.js 0 bytes {0} [built] \ No newline at end of file diff --git a/test/statsCases/color-enabled/index.js b/test/statsCases/color-enabled/index.js new file mode 100644 index 000000000..e69de29bb diff --git a/test/statsCases/color-enabled/webpack.config.js b/test/statsCases/color-enabled/webpack.config.js new file mode 100644 index 000000000..18037a235 --- /dev/null +++ b/test/statsCases/color-enabled/webpack.config.js @@ -0,0 +1,6 @@ +module.exports = { + entry: "./index", + stats: { + colors: true + } +};