From bf797cfccb33236d43bf120f6e7f69d722e18998 Mon Sep 17 00:00:00 2001 From: Katie Fenn Date: Mon, 18 Aug 2014 21:33:53 +0100 Subject: [PATCH 01/15] Added initial colour-coded human output, warnings output, and config controller event --- data/warning-figures-default.js | 16 +++++++++ data/warning-figures-strict.js | 0 lib/CliController.js | 5 ++- lib/Formatters.js | 36 -------------------- lib/formatters/.Warnings.js.swp | Bin 0 -> 12288 bytes lib/formatters/Csv.js | 15 +++++++++ lib/formatters/Human.js | 46 ++++++++++++++++++++++++++ lib/formatters/Json.js | 19 +++++++++++ lib/formatters/Warnings.js | 44 ++++++++++++++++++++++++ parker.js | 19 ++++++++--- test/CliController.js | 11 +++++- test/CliIntegration.js | 42 +++++++++++++++++++++++ test/fixtures/specificity-warning.css | 3 ++ 13 files changed, 213 insertions(+), 43 deletions(-) create mode 100644 data/warning-figures-default.js create mode 100644 data/warning-figures-strict.js create mode 100644 lib/formatters/.Warnings.js.swp create mode 100644 lib/formatters/Csv.js create mode 100644 lib/formatters/Human.js create mode 100644 lib/formatters/Json.js create mode 100644 lib/formatters/Warnings.js create mode 100644 test/CliIntegration.js create mode 100644 test/fixtures/specificity-warning.css diff --git a/data/warning-figures-default.js b/data/warning-figures-default.js new file mode 100644 index 0000000..30b4955 --- /dev/null +++ b/data/warning-figures-default.js @@ -0,0 +1,16 @@ +module.exports = { + 'total-stylesheets': [5, 7], + 'total-stylesheet-size': [168346.6, 284590.2], + 'total-rules': [1433.8, 2294.0], + 'total-selectors': [1948.8, 3317.3], + 'total-identifiers': [5185.2, 9714.6], + 'total-declarations': [3539.2, 5807.0], + 'selectors-per-rule': [1.4, 1.6], + 'identifiers-per-selector': [2.7, 3.2], + 'specificity-per-selector': [45.3, 59.6], + 'top-selector-specificity': [243.0, 322.0], + 'total-id-selectors': [55.0, 138.3], + 'total-unique-colours': [90, 132], + 'total-important-keywords': [69.9, 140], + 'total-media-queries': [10, 15] +}; diff --git a/data/warning-figures-strict.js b/data/warning-figures-strict.js new file mode 100644 index 0000000..e69de29 diff --git a/lib/CliController.js b/lib/CliController.js index 837ce8d..e0f0936 100644 --- a/lib/CliController.js +++ b/lib/CliController.js @@ -25,6 +25,9 @@ CliController.prototype.dispatch = function (argv) { if (argv.n || argv.numeric) { this.emit('showNumericOnly'); } + if (argv.config) { + this.emit('useConfig', argv.config); + } if (argv._ && argv._.length) { this.emit('runPaths', argv._); } @@ -37,4 +40,4 @@ CliController.prototype.dispatch = function (argv) { } }; -module.exports = CliController; \ No newline at end of file +module.exports = CliController; diff --git a/lib/Formatters.js b/lib/Formatters.js index fd728c6..e69de29 100644 --- a/lib/Formatters.js +++ b/lib/Formatters.js @@ -1,36 +0,0 @@ -/*! Parker v0.0.0 - MIT license */ - -'use strict'; - -var _ = require('underscore'), - clc = require('cli-color'); - - -// formats output as human-friendly text -exports.human = function (metrics, results) { - var logo = clc.red('PA') + clc.yellow('RK') + clc.green('ER') + '-JS' + "\n"; - return logo + _.reduce(metrics, function (str, metric) { - return str + metric.name + ': ' + results[metric.id] + '\n'; - }, ''); -}; - -// formats output as JSON -exports.json = function (metrics, results) { - var ids = _.map(metrics, function (metric) { - return metric.id; - }); - var obj = _.reduce(ids, function (obj, id) { - obj[id] = results[id]; - return obj; - }, {}); - return JSON.stringify(obj, null, 4); -}; - -exports.csv = function (metrics, results) { - var lineItems = []; - _.each(metrics, function (metric) { - lineItems.push('"' + results[metric.id] + '"'); - }); - - return lineItems.join(','); -} \ No newline at end of file diff --git a/lib/formatters/.Warnings.js.swp b/lib/formatters/.Warnings.js.swp new file mode 100644 index 0000000000000000000000000000000000000000..fb64f3fa64f235da68b758a61f70a2f6553b3816 GIT binary patch literal 12288 zcmeI2O>5LZ7{?!9F20K%MHp8wsqQANJyAx^KE)F?^ zgtDDz*UXptsTT*yUQ0CQC8qX=rM?i(d6AbmVeEV1>fLW)K(`)fnYa_4x+awy1~YCm zR&7sfsS@|1r=lQgCC=5Kn|Sr9xP=KYfo=k+Zq|mj(BQ#=ep9`-vPbOPalX3;-!lOw zzyz286JP>NfC(@GCh(sV(6ejkHr9x*`&p?L*EP$o#Uo#s025#WOn?b60Vco%m;e)C z0!)AjFoA!NfY%^;zJci8MwrL%|K<1p_uGixL9d{f&=cq`bO)+KHR$bDqSw$v$cHAO zOVDoU*%qQUWJAw46Fr5lLtCNs&^qYzCZbQ!N9Y6e0O~+zpfTtqGz=YvhM=$T_y&3m zJ%S!W_aWo`62yfGFaajO1egF5U;<3w?-A&9NT4XGQx%EYz%XUcd2QCx+oAVqh3@%4 z^X3HTuk?*tBS9-wGMQ{ktpb0vF*P|bHJq6Vn!?ToT%l8+xJk`4@^uhLq9yf+7lipp zBe5FKhFbP+Rg^QBcj-?}_Wy>-;(Y9H`0P}LW%cD)vgqWv6RnECnaX@g=FXHNwCExZ z2tV|l1sR6%yj>|=91#^X8%YfC&;@=Amw4Rsk3CumIdq0zb=SxXLNm`GtF^nGWs zZy#n~K7=?XdV*=9kQv3FA2?UCVOLCqktly?`xhNI7t^ZSuCcw;B95+>fQi&PI}hEn z@TAN{fb9zDoTqvL<>RiBGe0qOm5k3K4Z^q;BZkusSf;+T^SHyx;wG|@DW$V)hnTlJ zT?Wg9T6s~<6)!nGA5ExuRw}(vOt7@XVnQscxO198h*RVCl7YOT1Wjgs10}P5G)rNV z2-d`L%cNshN?T{g7OPrH%E-1(oXu*i+R3_Q68myg$#d6rMSfyE5pk+#Q!Tut z(bSF`X(%0eV>VVgf#Ky2L9Iydswm?C*CPKH3SW3f$?IvLq;2_OQ1jz3R%ZK} failFigure) { + return clc.red(result); + } + else if (result > warningFigure) { + return clc.yellow(result); + } + else if (result > -1) { + return clc.green(result); + } + + return result; +} diff --git a/lib/formatters/Json.js b/lib/formatters/Json.js new file mode 100644 index 0000000..8a744f5 --- /dev/null +++ b/lib/formatters/Json.js @@ -0,0 +1,19 @@ +/*! Parker v0.0.0 - MIT license */ + +'use strict'; + +var _ = require('underscore'), + clc = require('cli-color'); + +module.exports = function (metrics, results) { + // formats output as JSON + var ids = _.map(metrics, function (metric) { + return metric.id; + }); + var obj = _.reduce(ids, function (obj, id) { + obj[id] = results[id]; + return obj; + }, {}); + return JSON.stringify(obj, null, 4); +}; + diff --git a/lib/formatters/Warnings.js b/lib/formatters/Warnings.js new file mode 100644 index 0000000..1e8c401 --- /dev/null +++ b/lib/formatters/Warnings.js @@ -0,0 +1,44 @@ +/*! Parker v0.0.0 - MIT license */ + +'use strict'; + +var _ = require('underscore'), + clc = require('cli-color'); + +module.exports = function (metrics, results, settings) { + // formats output as warning list + var logo = clc.red('PA') + clc.yellow('RK') + clc.green('ER') + '-JS' + "\n"; + + metrics = metrics.filter(function (metric) { + return settings.warningFigures.hasOwnProperty(metric.id); + }); + + return logo + _.reduce(metrics, function (str, metric) { + var warningFigure = getWarningFigureForMetric(settings.warningFigures, metric.id), + failFigure = getFailFigureForMetric(settings.warningFigures, metric.id); + if (results[metric.id] && results[metric.id] > failFigure) { + return str + clc.red("Failure: " + metric.name + ": " + results[metric.id]) + '\n'; + } + else if (results[metric.id] && results[metric.id] > warningFigure) { + return str + clc.yellow("Warning: " + metric.name + ": " + results[metric.id]) + '\n'; + } + + return str; + }, ''); +} + +function getWarningFigureForMetric(warningFigures, metricId) { + if (warningFigures[metricId]) { + return warningFigures[metricId][0]; + } + + return -1; +} + +function getFailFigureForMetric(warningFigures, metricId) { + if (warningFigures[metricId]) { + return warningFigures[metricId][1]; + } + + return -1; +} diff --git a/parker.js b/parker.js index 48fa2fd..fccf804 100755 --- a/parker.js +++ b/parker.js @@ -12,12 +12,18 @@ var _ = require('underscore'), Parker = require('./lib/Parker'), CliController = require('./lib/CliController'), metrics = require('./metrics/All'), - formatters = require('./lib/Formatters'), + formatters = { + 'human': require('./lib/formatters/Human.js'), + 'json': require('./lib/formatters/Json.js'), + 'csv': require('./lib/formatters/Csv.js'), + 'warnings': require('./lib/formatters/Warnings.js') + }, argv = require('minimist')(process.argv.slice(2)), fs = require('fs'), async = require('async'), path = require('path'), - info = require('./lib/Info'); + info = require('./lib/Info'), + warningFigures = require('./data/warning-figures-default.js'); var cliController = new CliController(); @@ -106,8 +112,11 @@ var fileIsStylesheet = function (filePath) { }; var runReport = function (stylesheets, metrics) { - var results = parker.run(stylesheets); - console.log(formatter(metrics, results)); + var results = parker.run(stylesheets), + options = { + warningFigures: warningFigures + }; + console.log(formatter(metrics, results, options)); }; if (module.parent) { @@ -116,4 +125,4 @@ if (module.parent) { var parker = new Parker(metrics), formatter = formatters['human']; cliController.dispatch(argv); -} \ No newline at end of file +} diff --git a/test/CliController.js b/test/CliController.js index 8270655..8e127c0 100644 --- a/test/CliController.js +++ b/test/CliController.js @@ -81,6 +81,15 @@ describe('The CLI Controller', function() { expect(callback).to.have.been.calledWith('json'); }); + it('responds to a --config switch by dispatching a config event', function () { + var callback = sinon.spy(), + cliController = new CliController(); + + cliController.on('useConfig', callback); + cliController.dispatch({'config': './path/to/config.js'}); + expect(callback).to.have.been.calledWith('./path/to/config.js'); + }); + it('responds to no data supplied by dispatching a help event', function () { var callback = sinon.spy(), cliController = new CliController(); @@ -98,4 +107,4 @@ describe('The CLI Controller', function() { cliController.dispatch({'_': ['styles.css', 'ie.css']}); expect(pathsCallback).to.have.been.calledWith(['styles.css', 'ie.css']); }); -}); \ No newline at end of file +}); diff --git a/test/CliIntegration.js b/test/CliIntegration.js new file mode 100644 index 0000000..bd781c1 --- /dev/null +++ b/test/CliIntegration.js @@ -0,0 +1,42 @@ +/*! Parker v0.0.0 - MIT license */ + +var expect = require('chai').expect + exec = require('child_process').exec; + +describe('The Parker CLI tool', function () { + it('should display usage information when invoked with a -h or --help switch', function (done) { + exec('node parker.js -h', function (err, stdout, stderr) { + expect(stdout).to.contain('Usage:'); + done(); + }); + }); + + it('should display help information when invoked with no switches', function (done) { + exec('node parker.js', function (noSwitchErr, noSwitchStdout, noSwitchStderr) { + exec('node parker.js --help', function (helpErr, helpStdout, helpStderr) { + expect(noSwitchStdout).to.equal(helpStdout); + done(); + }); + }); + }); + + it('should display warnings only when invoked with a --format="warnings" switch', function (done) { + exec('node parker.js test/fixtures/specificity-warning.css --format="warnings"', function (err, stdout, stderr) { + expect(stdout).to.contain('Failure: Top Selector Specificity: 900'); + expect(stdout).to.contain('Failure: Specificity Per Selector: 900'); + expect(stdout).to.contain('Failure: Top Selector Specificity: 900'); + done(); + }); + }); + + it( + 'should not report results for metrics with no configured warning' + + ' figure when invoked with a --format="warnings" switch', + function (done) { + exec('node parker.js test/fixtures/specificity-warning.css --format="warnings"', function (err, stdout, stderr) { + expect(stdout).to.not.contain('Failure: Media Queries:'); + done(); + }); + } + ); +}); diff --git a/test/fixtures/specificity-warning.css b/test/fixtures/specificity-warning.css new file mode 100644 index 0000000..d8ee4a8 --- /dev/null +++ b/test/fixtures/specificity-warning.css @@ -0,0 +1,3 @@ +#a #b #c #d #e #f #g #h #i { + font-weight: bold; +} From b7b81c1495229ec0af4f33dbf4b995bc3c12bae4 Mon Sep 17 00:00:00 2001 From: Katie Fenn Date: Mon, 18 Aug 2014 21:34:28 +0100 Subject: [PATCH 02/15] Removed redundant lib/Formatters.js file --- lib/Formatters.js | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 lib/Formatters.js diff --git a/lib/Formatters.js b/lib/Formatters.js deleted file mode 100644 index e69de29..0000000 From eff40ddffb250086f535fda3420d187f0abb4bf2 Mon Sep 17 00:00:00 2001 From: Katie Fenn Date: Mon, 25 Aug 2014 18:22:21 +0100 Subject: [PATCH 03/15] Added support for configuration files, warnings format output, several code style fixes --- lib/CliController.js | 3 -- lib/CliFormatter.js | 6 +-- lib/ConfigController.js | 29 ++++++++++ lib/CssMediaQuery.js | 22 ++++---- lib/CssStylesheet.js | 32 +++++------ lib/Parker.js | 4 +- lib/formatters/.Warnings.js.swp | Bin 12288 -> 0 bytes lib/formatters/Csv.js | 2 +- lib/formatters/Human.js | 4 +- lib/formatters/Warnings.js | 10 ++-- metrics/TotalUniqueColours.js | 4 +- metrics/UniqueColours.js | 4 +- package.json | 3 +- parker.js | 31 ++++++++--- test/CliController.js | 29 ++++------ test/CliIntegration.js | 31 ++++++++--- test/ConfigController.js | 50 ++++++++++++++++++ test/CssRule.js | 4 +- test/Parker.js | 12 ++--- test/TopSelectorSpecificity.js | 12 ++--- .../fixtures/config-with-warning-figures.json | 10 ++++ test/fixtures/minimal-config.json | 3 ++ test/fixtures/specificity-warning.css | 1 + 23 files changed, 208 insertions(+), 98 deletions(-) create mode 100644 lib/ConfigController.js delete mode 100644 lib/formatters/.Warnings.js.swp create mode 100644 test/ConfigController.js create mode 100644 test/fixtures/config-with-warning-figures.json create mode 100644 test/fixtures/minimal-config.json diff --git a/lib/CliController.js b/lib/CliController.js index e0f0936..eafb10e 100644 --- a/lib/CliController.js +++ b/lib/CliController.js @@ -25,9 +25,6 @@ CliController.prototype.dispatch = function (argv) { if (argv.n || argv.numeric) { this.emit('showNumericOnly'); } - if (argv.config) { - this.emit('useConfig', argv.config); - } if (argv._ && argv._.length) { this.emit('runPaths', argv._); } diff --git a/lib/CliFormatter.js b/lib/CliFormatter.js index 30ed7a5..354442e 100644 --- a/lib/CliFormatter.js +++ b/lib/CliFormatter.js @@ -9,13 +9,13 @@ function CliFormatter() { } CliFormatter.prototype.format = function (data, metrics) { - var output = ''; + var output = ''; _.each(metrics, function(metric) { output += metric.name + ": " + data[metric.id]; output += "\n"; }); - return output; + return output; }; -module.exports = CliFormatter; \ No newline at end of file +module.exports = CliFormatter; diff --git a/lib/ConfigController.js b/lib/ConfigController.js new file mode 100644 index 0000000..7b0c708 --- /dev/null +++ b/lib/ConfigController.js @@ -0,0 +1,29 @@ +/*! Parker v0.0.0 - MIT license */ + +'use strict'; + +var util = require('util'), + events = require('events'); + +function ConfigController() { + events.EventEmitter.call(this); +} + +util.inherits(ConfigController, events.EventEmitter); + +ConfigController.prototype.dispatch = function (config) { + if (config.files) { + this.emit('runPaths', config.files); + } + if (config.format) { + this.emit('setFormat', config.format); + } + if (config['show-numeric-only']) { + this.emit('showNumericOnly'); + } + if (config['warning-figures']) { + this.emit('customWarningFigures', config['warning-figures']); + } +}; + +module.exports = ConfigController; diff --git a/lib/CssMediaQuery.js b/lib/CssMediaQuery.js index 8b70c5c..5391315 100644 --- a/lib/CssMediaQuery.js +++ b/lib/CssMediaQuery.js @@ -3,14 +3,14 @@ 'use strict'; function CssMediaQuery(raw) { - this.raw = raw; + this.raw = raw; } CssMediaQuery.prototype.getQueries = function () { - var pattern = /@media\w*(.+?)\s?{/, - queries = pattern.exec(this.raw)[1]; + var pattern = /@media\w*(.+?)\s?{/, + queries = pattern.exec(this.raw)[1]; - return queries.split(/ or |,/g).map(trimQuery); + return queries.split(/ or |,/g).map(trimQuery); }; CssMediaQuery.prototype.getRules = function () { @@ -19,17 +19,17 @@ CssMediaQuery.prototype.getRules = function () { rule = ''; for (var index = 0; index < this.raw.length; index++) { - if (depth > 0) { - rule += this.raw.charAt(index); - } + if (depth > 0) { + rule += this.raw.charAt(index); + } if (this.raw.charAt(index) === '{') { depth ++; } - else if (this.raw.charAt(index) == '}') { + else if (this.raw.charAt(index) === '}') { depth --; } - if (depth === 1 && this.raw.charAt(index) == '}') { + if (depth === 1 && this.raw.charAt(index) === '}') { rules.push(rule.trim()); rule = ''; } @@ -38,7 +38,7 @@ CssMediaQuery.prototype.getRules = function () { }; var trimQuery = function (query) { - return query.trim(); + return query.trim(); }; -module.exports = CssMediaQuery; \ No newline at end of file +module.exports = CssMediaQuery; diff --git a/lib/CssStylesheet.js b/lib/CssStylesheet.js index 383ef78..6c8bbdf 100644 --- a/lib/CssStylesheet.js +++ b/lib/CssStylesheet.js @@ -42,7 +42,7 @@ var getChildren = function (raw) { if (stylesheet.charAt(index) === '{') { depth ++; } - else if (stylesheet.charAt(index) == '}') { + else if (stylesheet.charAt(index) === '}') { depth --; } @@ -54,40 +54,40 @@ var getChildren = function (raw) { return children; }; -var stripComments = function (string) { +function stripComments (string) { return string.replace(/\/\*.+?\*\//g, ''); -}; +} -var stripFormatting = function (string) { +function stripFormatting (string) { return stripNewlines(trimWhitespace(string)); -}; +} -var trimWhitespace = function (string) { +function trimWhitespace (string) { return string.replace(/[ ]+/g, ' '); -}; +} -var stripNewlines = function (string) { +function stripNewlines(string) { return string.replace(/\n|\r|\r\n/g, ''); -}; +} -var isRule = function (string) { +function isRule(string) { return !isMediaQuery(string) && hasRuleBlock(string) && hasSelectorBlock(string); } -var isMalformedStatement = function (string) { +function isMalformedStatement(string) { return !isRule(string) && !isMediaQuery(string); } -var hasRuleBlock = function (string) { +function hasRuleBlock(string) { return string.indexOf('{') !== -1 && string.indexOf('}') !== -1; } -var hasSelectorBlock = function (string) { - return string.match(/^[^\{]+/g) +function hasSelectorBlock(string) { + return string.match(/^[^\{]+/g); } -var isMediaQuery = function (string) { +function isMediaQuery(string) { return string.match(/^@media/g); } -module.exports = CssStylesheet; \ No newline at end of file +module.exports = CssStylesheet; diff --git a/lib/Parker.js b/lib/Parker.js index 17a6578..60ea748 100644 --- a/lib/Parker.js +++ b/lib/Parker.js @@ -37,7 +37,7 @@ var runMetrics = function (metrics, stylesheets) { _.each(stylesheets, function (rawStylesheet) { readings.push(runMetricsOnNode(metrics, rawStylesheet, 'stylesheet')); - + var stylesheet = new CssStylesheet(rawStylesheet), rules = stylesheet.getRules() || []; @@ -197,4 +197,4 @@ var filterMetricsByType = function (metrics, type) { return metrics; }; -module.exports = Parker; \ No newline at end of file +module.exports = Parker; diff --git a/lib/formatters/.Warnings.js.swp b/lib/formatters/.Warnings.js.swp deleted file mode 100644 index fb64f3fa64f235da68b758a61f70a2f6553b3816..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12288 zcmeI2O>5LZ7{?!9F20K%MHp8wsqQANJyAx^KE)F?^ zgtDDz*UXptsTT*yUQ0CQC8qX=rM?i(d6AbmVeEV1>fLW)K(`)fnYa_4x+awy1~YCm zR&7sfsS@|1r=lQgCC=5Kn|Sr9xP=KYfo=k+Zq|mj(BQ#=ep9`-vPbOPalX3;-!lOw zzyz286JP>NfC(@GCh(sV(6ejkHr9x*`&p?L*EP$o#Uo#s025#WOn?b60Vco%m;e)C z0!)AjFoA!NfY%^;zJci8MwrL%|K<1p_uGixL9d{f&=cq`bO)+KHR$bDqSw$v$cHAO zOVDoU*%qQUWJAw46Fr5lLtCNs&^qYzCZbQ!N9Y6e0O~+zpfTtqGz=YvhM=$T_y&3m zJ%S!W_aWo`62yfGFaajO1egF5U;<3w?-A&9NT4XGQx%EYz%XUcd2QCx+oAVqh3@%4 z^X3HTuk?*tBS9-wGMQ{ktpb0vF*P|bHJq6Vn!?ToT%l8+xJk`4@^uhLq9yf+7lipp zBe5FKhFbP+Rg^QBcj-?}_Wy>-;(Y9H`0P}LW%cD)vgqWv6RnECnaX@g=FXHNwCExZ z2tV|l1sR6%yj>|=91#^X8%YfC&;@=Amw4Rsk3CumIdq0zb=SxXLNm`GtF^nGWs zZy#n~K7=?XdV*=9kQv3FA2?UCVOLCqktly?`xhNI7t^ZSuCcw;B95+>fQi&PI}hEn z@TAN{fb9zDoTqvL<>RiBGe0qOm5k3K4Z^q;BZkusSf;+T^SHyx;wG|@DW$V)hnTlJ zT?Wg9T6s~<6)!nGA5ExuRw}(vOt7@XVnQscxO198h*RVCl7YOT1Wjgs10}P5G)rNV z2-d`L%cNshN?T{g7OPrH%E-1(oXu*i+R3_Q68myg$#d6rMSfyE5pk+#Q!Tut z(bSF`X(%0eV>VVgf#Ky2L9Iydswm?C*CPKH3SW3f$?IvLq;2_OQ1jz3R%ZK} failFigure) { + if (result >= failFigure) { return clc.red(result); } - else if (result > warningFigure) { + else if (result >= warningFigure) { return clc.yellow(result); } else if (result > -1) { diff --git a/lib/formatters/Warnings.js b/lib/formatters/Warnings.js index 1e8c401..75f850e 100644 --- a/lib/formatters/Warnings.js +++ b/lib/formatters/Warnings.js @@ -5,10 +5,10 @@ var _ = require('underscore'), clc = require('cli-color'); -module.exports = function (metrics, results, settings) { +module.exports = function (metrics, results, settings) { // formats output as warning list var logo = clc.red('PA') + clc.yellow('RK') + clc.green('ER') + '-JS' + "\n"; - + metrics = metrics.filter(function (metric) { return settings.warningFigures.hasOwnProperty(metric.id); }); @@ -16,16 +16,16 @@ module.exports = function (metrics, results, settings) { return logo + _.reduce(metrics, function (str, metric) { var warningFigure = getWarningFigureForMetric(settings.warningFigures, metric.id), failFigure = getFailFigureForMetric(settings.warningFigures, metric.id); - if (results[metric.id] && results[metric.id] > failFigure) { + if (results[metric.id] && results[metric.id] >= failFigure) { return str + clc.red("Failure: " + metric.name + ": " + results[metric.id]) + '\n'; } - else if (results[metric.id] && results[metric.id] > warningFigure) { + else if (results[metric.id] && results[metric.id] >= warningFigure) { return str + clc.yellow("Warning: " + metric.name + ": " + results[metric.id]) + '\n'; } return str; }, ''); -} +}; function getWarningFigureForMetric(warningFigures, metricId) { if (warningFigures[metricId]) { diff --git a/metrics/TotalUniqueColours.js b/metrics/TotalUniqueColours.js index e12aef2..6d70ad8 100644 --- a/metrics/TotalUniqueColours.js +++ b/metrics/TotalUniqueColours.js @@ -6,7 +6,7 @@ var _ = require('underscore'); module.exports = { id: 'total-unique-colours', - name: 'Total Unique Colors', + name: 'Total Unique Colours', type: 'value', aggregate: 'length', format: 'number', @@ -39,4 +39,4 @@ var getLongHashForm = function (string) { } return string; -}; \ No newline at end of file +}; diff --git a/metrics/UniqueColours.js b/metrics/UniqueColours.js index 9a9e91c..b309af0 100644 --- a/metrics/UniqueColours.js +++ b/metrics/UniqueColours.js @@ -6,7 +6,7 @@ var _ = require('underscore'); module.exports = { id: 'unique-colours', - name: 'Unique Colors', + name: 'Unique Colours', type: 'value', aggregate: 'list', format: 'list', @@ -39,4 +39,4 @@ var getLongHashForm = function (string) { } return string; -}; \ No newline at end of file +}; diff --git a/package.json b/package.json index 2976a79..0259179 100644 --- a/package.json +++ b/package.json @@ -14,7 +14,8 @@ "chai": "*", "mocha": "*", "sinon": "*", - "sinon-chai": "*" + "sinon-chai": "*", + "jshint": "~2.5.5" }, "scripts": { "test": "mocha --no-colors --reporter spec" diff --git a/parker.js b/parker.js index fccf804..e89dcc5 100755 --- a/parker.js +++ b/parker.js @@ -11,6 +11,7 @@ var _ = require('underscore'), Parker = require('./lib/Parker'), CliController = require('./lib/CliController'), + ConfigController = require('./lib/ConfigController'), metrics = require('./metrics/All'), formatters = { 'human': require('./lib/formatters/Human.js'), @@ -25,9 +26,13 @@ var _ = require('underscore'), info = require('./lib/Info'), warningFigures = require('./data/warning-figures-default.js'); -var cliController = new CliController(); +if (argv.config) { + var controller = new ConfigController(); +} else { + var controller = new CliController(); +} -cliController.on('runPaths', function (filePaths) { +controller.on('runPaths', function (filePaths) { var stylesheets = []; async.each(filePaths, function (filePath, onAllLoad) { var onFileLoad = function (err, data) { @@ -46,7 +51,7 @@ cliController.on('runPaths', function (filePaths) { }); }); -cliController.on('runStdin', function () { +controller.on('runStdin', function () { process.stdin.resume(); process.stdin.setEncoding('utf8'); var stdinData = ''; @@ -60,17 +65,17 @@ cliController.on('runStdin', function () { }); }); -cliController.on('showVersion', function () { +controller.on('showVersion', function () { info.version(); process.exit(); }); -cliController.on('showHelp', function () { +controller.on('showHelp', function () { info.help(); process.exit(); }); -cliController.on('setFormat', function (format) { +controller.on('setFormat', function (format) { formatter = formatters[format]; if (!formatter) { @@ -80,12 +85,16 @@ cliController.on('setFormat', function (format) { } }); -cliController.on('showNumericOnly', function () { +controller.on('showNumericOnly', function () { metrics = _.filter(metrics, function (metric) { return metric.format == 'number'; }); }); +controller.on('customWarningFigures', function (customWarningFigures) { + warningFigures = customWarningFigures; +}); + var readDirectory = function (directoryPath, onFileLoad, onAllLoad) { fs.readdir(directoryPath, function (err, files) { async.each(files, function (file, fileDone) { @@ -124,5 +133,11 @@ if (module.parent) { } else { var parker = new Parker(metrics), formatter = formatters['human']; - cliController.dispatch(argv); + if (argv.config) { + readFile(argv.config, function (err, filedata) { + controller.dispatch(JSON.parse(filedata)); + }); + } else { + controller.dispatch(argv); + } } diff --git a/test/CliController.js b/test/CliController.js index 8e127c0..ab83a1a 100644 --- a/test/CliController.js +++ b/test/CliController.js @@ -12,7 +12,7 @@ describe('The CLI Controller', function() { it('responds to a -v switch by dispatching a version event', function () { var callback = sinon.spy(), cliController = new CliController(); - + cliController.on('showVersion', callback); cliController.dispatch({'v': true}); expect(callback).to.have.been.called; @@ -21,7 +21,7 @@ describe('The CLI Controller', function() { it('responds to a --version switch by dispatching a version event', function () { var callback = sinon.spy(), cliController = new CliController(); - + cliController.on('showVersion', callback); cliController.dispatch({'version': true}); expect(callback).to.have.been.called; @@ -30,7 +30,7 @@ describe('The CLI Controller', function() { it('responds to a -h switch by dispatching a version event', function () { var callback = sinon.spy(), cliController = new CliController(); - + cliController.on('showHelp', callback); cliController.dispatch({'h': true}); expect(callback).to.have.been.called; @@ -39,7 +39,7 @@ describe('The CLI Controller', function() { it('responds to a --help switch by dispatching a version event', function () { var callback = sinon.spy(), cliController = new CliController(); - + cliController.on('showHelp', callback); cliController.dispatch({'help': true}); expect(callback).to.have.been.called; @@ -48,7 +48,7 @@ describe('The CLI Controller', function() { it('responds to a -h switch by dispatching a help event', function () { var callback = sinon.spy(), cliController = new CliController(); - + cliController.on('showHelp', callback); cliController.dispatch({'h': true}); expect(callback).to.have.been.called; @@ -57,7 +57,7 @@ describe('The CLI Controller', function() { it('responds to a --help switch by dispatching a help event', function () { var callback = sinon.spy(), cliController = new CliController(); - + cliController.on('showHelp', callback); cliController.dispatch({'h': true}); expect(callback).to.have.been.called; @@ -66,7 +66,7 @@ describe('The CLI Controller', function() { it('responds to a -f switch by dispatching a format event', function () { var callback = sinon.spy(), cliController = new CliController(); - + cliController.on('setFormat', callback); cliController.dispatch({'f': 'json'}); expect(callback).to.have.been.calledWith('json'); @@ -75,25 +75,16 @@ describe('The CLI Controller', function() { it('responds to a --format switch by dispatching a format event', function () { var callback = sinon.spy(), cliController = new CliController(); - + cliController.on('setFormat', callback); cliController.dispatch({'format': 'json'}); expect(callback).to.have.been.calledWith('json'); }); - it('responds to a --config switch by dispatching a config event', function () { - var callback = sinon.spy(), - cliController = new CliController(); - - cliController.on('useConfig', callback); - cliController.dispatch({'config': './path/to/config.js'}); - expect(callback).to.have.been.calledWith('./path/to/config.js'); - }); - it('responds to no data supplied by dispatching a help event', function () { var callback = sinon.spy(), cliController = new CliController(); - + cliController.on('showHelp', callback); cliController.dispatch({}); expect(callback).to.have.been.called; @@ -102,7 +93,7 @@ describe('The CLI Controller', function() { it('responds to unnamed arguments by dispatching file event, then a run event', function () { var pathsCallback = sinon.spy(), cliController = new CliController(); - + cliController.on('runPaths', pathsCallback); cliController.dispatch({'_': ['styles.css', 'ie.css']}); expect(pathsCallback).to.have.been.calledWith(['styles.css', 'ie.css']); diff --git a/test/CliIntegration.js b/test/CliIntegration.js index bd781c1..5e62510 100644 --- a/test/CliIntegration.js +++ b/test/CliIntegration.js @@ -17,18 +17,18 @@ describe('The Parker CLI tool', function () { expect(noSwitchStdout).to.equal(helpStdout); done(); }); - }); + }); }); - + it('should display warnings only when invoked with a --format="warnings" switch', function (done) { exec('node parker.js test/fixtures/specificity-warning.css --format="warnings"', function (err, stdout, stderr) { expect(stdout).to.contain('Failure: Top Selector Specificity: 900'); expect(stdout).to.contain('Failure: Specificity Per Selector: 900'); expect(stdout).to.contain('Failure: Top Selector Specificity: 900'); - done(); - }); + done(); + }); }); - + it( 'should not report results for metrics with no configured warning' + ' figure when invoked with a --format="warnings" switch', @@ -37,6 +37,23 @@ describe('The Parker CLI tool', function () { expect(stdout).to.not.contain('Failure: Media Queries:'); done(); }); - } - ); + } + ); + + it('should load settings from a config file when invoked with a --config="" switch', function (done) { + exec('node parker.js --config="test/fixtures/minimal-config.json"', function (err, stdout, stderr) { + expect(stdout).to.not.contain('Usage:'); + expect(stdout).to.contain('Total Stylesheets'); + done(); + }); + }); + + it('should load custom warning figures when invoked with a config file containing them', function (done) { + exec('node parker.js --config="test/fixtures/config-with-warning-figures.json"', function (err, stdout, stderr) { + expect(stdout).to.not.contain('Failure: Top Selector Specificity'); + expect(stdout).to.contain('Warning: Total Unique Colours'); + expect(stdout).to.contain('Failure: Selectors Per Rule'); + done(); + }); + }); }); diff --git a/test/ConfigController.js b/test/ConfigController.js new file mode 100644 index 0000000..cf7d4e6 --- /dev/null +++ b/test/ConfigController.js @@ -0,0 +1,50 @@ +/*! Parker v0.0.0 - MIT license */ + +var chai = require('chai'), + expect = require('chai').expect, + ConfigController = require('../lib/ConfigController.js'), + sinon = require('sinon'), + sinonChai = require('sinon-chai'); + +chai.use(sinonChai); + +describe('The Config Controller', function() { + it('responds to a "files" setting by dispatching a files event', function () { + var callback = sinon.spy(), + files = ['path/to/files.js'] + configController = new ConfigController(); + + configController.on('runPaths', callback); + configController.dispatch({'files': files}); + expect(callback).to.have.been.calledWith(files); + }); + + it('responds to a "show-numeric-only" setting by dispatching a files event', function () { + var callback = sinon.spy(), + files = ['path/to/files.js'] + configController = new ConfigController(); + + configController.on('showNumericOnly', callback); + configController.dispatch({'show-numeric-only': true}); + expect(callback).to.have.been.called; + }); + + it('responds to a "format" setting by dispatching a format event', function () { + var callback = sinon.spy(), + configController = new ConfigController(); + + configController.on('setFormat', callback); + configController.dispatch({'format': 'json'}); + expect(callback).to.have.been.calledWith('json'); + }); + + it('responds to a "warning-figures" setting by dispatching a custom warning figures event', function () { + var callback = sinon.spy(), + warningFigures = {'top-selector-specificity': [50, 99]}, + configController = new ConfigController(); + + configController.on('customWarningFigures', callback); + configController.dispatch({'warning-figures': warningFigures}); + expect(callback).to.have.been.calledWith(warningFigures); + }); +}); diff --git a/test/CssRule.js b/test/CssRule.js index fcd2a1f..f3be788 100644 --- a/test/CssRule.js +++ b/test/CssRule.js @@ -22,7 +22,7 @@ describe('The Rule Parser', function () { var complexRule = 'body, html, .container .wrapper, #container, .container a[rel="blah"]' + '{background: url(img.png); background-color: linear-gradient(45deg, #00f, #f00)}'; cssRule = new CssRule(complexRule); - + expect(cssRule.getDeclarations()).to.have.length(2); }); -}); \ No newline at end of file +}); diff --git a/test/Parker.js b/test/Parker.js index 2ec6826..7f903ff 100644 --- a/test/Parker.js +++ b/test/Parker.js @@ -31,7 +31,6 @@ describe('The Parker tool', function() { parker = new Parker([mockMetric]); var report = parker.run([stylesheet, stylesheet, stylesheet]); - expect(report).to.have.property('mock-stylesheet-metric'); expect(report['mock-stylesheet-metric']).to.equal(3); }); @@ -43,7 +42,6 @@ describe('The Parker tool', function() { parker = new Parker([mockMetric]); var report = parker.run([stylesheet, stylesheet, stylesheet]); - expect(report).to.have.property('mock-stylesheet-metric'); expect(report['mock-stylesheet-metric']).to.equal(0); }); @@ -55,7 +53,6 @@ describe('The Parker tool', function() { parker = new Parker([mockMetric]); var report = parker.run([stylesheet, stylesheet, stylesheet]); - expect(report).to.have.property('mock-stylesheet-metric'); expect(report['mock-stylesheet-metric']).to.equal(1); }); @@ -67,7 +64,6 @@ describe('The Parker tool', function() { parker = new Parker([mockMetric]); var report = parker.run([stylesheet]); - expect(report).to.have.property('mock-stylesheet-metric'); expect(report['mock-stylesheet-metric']).to.equal(0); }); @@ -76,7 +72,7 @@ describe('The Parker tool', function() { var mockIntMetric = {id: 'mock-int-metric', type: 'stylesheet', aggregate: 'max', measure: function(stylesheet) {return stylesheet.length;}}, parker = new Parker([mockIntMetric]), report = parker.run(['body {background: #FFF;}', 'body {background: #FFFFFF;}']); - + expect(report).to.have.property('mock-int-metric'); expect(report['mock-int-metric']).to.equal(27); }); @@ -85,7 +81,7 @@ describe('The Parker tool', function() { var mockIntMetric = {id: 'mock-int-metric', type: 'rule', aggregate: 'max', measure: function(stylesheet) {return stylesheet.length;}}, parker = new Parker([mockIntMetric]), report = parker.run(['/* comment */']); - + expect(report).to.have.property('mock-int-metric'); expect(report['mock-int-metric']).to.equal(0); }); @@ -94,7 +90,7 @@ describe('The Parker tool', function() { var mockStringMetric = {id: 'mock-string-metric', type: 'stylesheet', aggregate: 'max', measure: function(stylesheet) {return stylesheet;}, iterator: function(string) {return string.length}}, parker = new Parker([mockStringMetric]), report = parker.run(['body {background: #FFF;}', 'body {background: #FFFFFF;}']); - + expect(report).to.have.property('mock-string-metric'); expect(report['mock-string-metric']).to.equal('body {background: #FFFFFF;}'); }); @@ -218,4 +214,4 @@ describe('The Parker tool', function() { expect(report).to.have.property('mock-media-query-metric'); expect(report['mock-media-query-metric']).to.equal(0); }); -}); \ No newline at end of file +}); diff --git a/test/TopSelectorSpecificity.js b/test/TopSelectorSpecificity.js index c7c4dd0..40935e9 100644 --- a/test/TopSelectorSpecificity.js +++ b/test/TopSelectorSpecificity.js @@ -2,9 +2,9 @@ var expect = require('chai').expect, metric = require('../metrics/TopSelectorSpecificity.js'); describe('The top-selector-specificity metric', function () { - it('should count only the specificity of the child selector of a :not identifier', function () { - expect(metric.measure(':not(body)')).to.equal(1); - expect(metric.measure(':not(.sidebar)')).to.equal(10); - expect(metric.measure(':not(h1#main)')).to.equal(101); - }); -}); \ No newline at end of file + it('should count only the specificity of the child selector of a :not identifier', function () { + expect(metric.measure(':not(body)')).to.equal(1); + expect(metric.measure(':not(.sidebar)')).to.equal(10); + expect(metric.measure(':not(h1#main)')).to.equal(101); + }); +}); diff --git a/test/fixtures/config-with-warning-figures.json b/test/fixtures/config-with-warning-figures.json new file mode 100644 index 0000000..207339a --- /dev/null +++ b/test/fixtures/config-with-warning-figures.json @@ -0,0 +1,10 @@ +{ + "files": ["test/fixtures/specificity-warning.css"], + "format": "warnings", + "show-numeric-only": true, + "warning-figures": { + "top-selector-specificity": [990, 999], + "total-unique-colours": [1, 2], + "selectors-per-rule": [0, 1] + } +} diff --git a/test/fixtures/minimal-config.json b/test/fixtures/minimal-config.json new file mode 100644 index 0000000..b4970ff --- /dev/null +++ b/test/fixtures/minimal-config.json @@ -0,0 +1,3 @@ +{ + "files": ["test/fixtures/specificity-warning.css"] +} diff --git a/test/fixtures/specificity-warning.css b/test/fixtures/specificity-warning.css index d8ee4a8..16a808d 100644 --- a/test/fixtures/specificity-warning.css +++ b/test/fixtures/specificity-warning.css @@ -1,3 +1,4 @@ #a #b #c #d #e #f #g #h #i { font-weight: bold; + color: #fff; } From 7855d7a5cf58d828b7153d8cf4d40733ab1630f2 Mon Sep 17 00:00:00 2001 From: Katie Fenn Date: Tue, 26 Aug 2014 21:07:01 +0100 Subject: [PATCH 04/15] Removal of jshint dev-dependency --- package.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/package.json b/package.json index 0259179..2976a79 100644 --- a/package.json +++ b/package.json @@ -14,8 +14,7 @@ "chai": "*", "mocha": "*", "sinon": "*", - "sinon-chai": "*", - "jshint": "~2.5.5" + "sinon-chai": "*" }, "scripts": { "test": "mocha --no-colors --reporter spec" From e89c879a40540286731d7123aa2be3c5f8a9f0df Mon Sep 17 00:00:00 2001 From: Katie Fenn Date: Sun, 31 Aug 2014 11:17:44 +0100 Subject: [PATCH 05/15] Added exit error codes, surpress-colours option, configurable warning figures, colour-coded resules and warnings output formatter --- data/warning-figures-default.js | 28 +++++++-------- data/warning-figures-strict.js | 16 +++++++++ lib/CliController.js | 10 ++++++ lib/ConfigController.js | 5 ++- lib/formatters/Human.js | 22 +++++++++--- lib/formatters/Warnings.js | 57 ++++++++++++++++++++++++------- parker.js | 37 +++++++++++++++++--- test/CliController.js | 27 +++++++++++++++ test/CliIntegration.js | 51 +++++++++++++++++++++------ test/ConfigController.js | 13 ++++++- test/fixtures/one-id-selector.css | 3 ++ 11 files changed, 223 insertions(+), 46 deletions(-) create mode 100644 test/fixtures/one-id-selector.css diff --git a/data/warning-figures-default.js b/data/warning-figures-default.js index 30b4955..dc50789 100644 --- a/data/warning-figures-default.js +++ b/data/warning-figures-default.js @@ -1,16 +1,16 @@ module.exports = { - 'total-stylesheets': [5, 7], - 'total-stylesheet-size': [168346.6, 284590.2], - 'total-rules': [1433.8, 2294.0], - 'total-selectors': [1948.8, 3317.3], - 'total-identifiers': [5185.2, 9714.6], - 'total-declarations': [3539.2, 5807.0], - 'selectors-per-rule': [1.4, 1.6], - 'identifiers-per-selector': [2.7, 3.2], - 'specificity-per-selector': [45.3, 59.6], - 'top-selector-specificity': [243.0, 322.0], - 'total-id-selectors': [55.0, 138.3], - 'total-unique-colours': [90, 132], - 'total-important-keywords': [69.9, 140], - 'total-media-queries': [10, 15] + 'total-stylesheets': [6, 9], + 'total-stylesheet-size': [234767, 377908.0], + 'total-rules': [1965.4, 2789.8], + 'total-selectors': [2780.4, 4095.6], + 'total-identifiers': [8249.8, 11383.8], + 'total-declarations': [4884, 7226.8], + 'selectors-per-rule': [1.5, 1.6], + 'identifiers-per-selector': [3.0, 3.6], + 'specificity-per-selector': [53.7, 70.6], + 'top-selector-specificity': [311.0, 362], + 'total-id-selectors': [96.4, 188.4], + 'total-unique-colours': [112.0, 158.2], + 'total-important-keywords': [115.4, 179.0], + 'total-media-queries': [16, 24] }; diff --git a/data/warning-figures-strict.js b/data/warning-figures-strict.js index e69de29..001e3ff 100644 --- a/data/warning-figures-strict.js +++ b/data/warning-figures-strict.js @@ -0,0 +1,16 @@ +module.exports = { + 'total-stylesheets': [3, 4], + 'total-stylesheet-size': [56764.4, 84259], + 'total-rules': [529.4, 762], + 'total-selectors': [724.2, 990], + 'total-identifiers': [1654.2, 2415], + 'total-declarations': [1395, 1981], + 'selectors-per-rule': [1.2, 1.3], + 'identifiers-per-selector': [2.2, 2.4], + 'specificity-per-selector': [27.4, 32.5], + 'top-selector-specificity': [90, 100], + 'total-id-selectors': [6, 13], + 'total-unique-colours': [41, 58], + 'total-important-keywords': [15.0, 29], + 'total-media-queries': [5, 6.0] +}; diff --git a/lib/CliController.js b/lib/CliController.js index eafb10e..d9e8454 100644 --- a/lib/CliController.js +++ b/lib/CliController.js @@ -25,6 +25,16 @@ CliController.prototype.dispatch = function (argv) { if (argv.n || argv.numeric) { this.emit('showNumericOnly'); } + if (argv['warning-figures']) { + var warningFigures = argv['warning-figures']; + this.emit('setWarningFigures', warningFigures); + } + if (argv.strict) { + this.emit('setWarningFigures', 'strict'); + } + if (argv['surpress-colours']) { + this.emit('setSurpressColours'); + } if (argv._ && argv._.length) { this.emit('runPaths', argv._); } diff --git a/lib/ConfigController.js b/lib/ConfigController.js index 7b0c708..ee450f8 100644 --- a/lib/ConfigController.js +++ b/lib/ConfigController.js @@ -22,7 +22,10 @@ ConfigController.prototype.dispatch = function (config) { this.emit('showNumericOnly'); } if (config['warning-figures']) { - this.emit('customWarningFigures', config['warning-figures']); + this.emit('setWarningFigures', config['warning-figures']); + } + if (config['surpress-colours']) { + this.emit('setSurpressColours'); } }; diff --git a/lib/formatters/Human.js b/lib/formatters/Human.js index 778affe..24102c2 100644 --- a/lib/formatters/Human.js +++ b/lib/formatters/Human.js @@ -3,15 +3,25 @@ 'use strict'; var _ = require('underscore'), - clc = require('cli-color'); + clc = require('cli-color'), + nonColourCodedLogo = "PARKER-JS\n", + colourCodedLogo = clc.red('PA') + clc.yellow('RK') + clc.green('ER') + '-JS' + "\n"; module.exports = function (metrics, results, settings) { // formats output as human-friendly text - var logo = clc.red('PA') + clc.yellow('RK') + clc.green('ER') + '-JS' + "\n"; + + if (settings.surpressColours) { + var resultFormatter = formatResult, + logo = nonColourCodedLogo; + } else { + var resultFormatter = formatColourCodedResult, + logo = colourCodedLogo; + } + return logo + _.reduce(metrics, function (str, metric) { var warningFigure = getWarningFigureForMetric(settings.warningFigures, metric.id), failFigure = getFailFigureForMetric(settings.warningFigures, metric.id); - return str + metric.name + ': ' + colourCodeResult(results[metric.id], warningFigure, failFigure) + '\n'; + return str + metric.name + ': ' + resultFormatter(results[metric.id], warningFigure, failFigure) + '\n'; }, ''); }; @@ -31,7 +41,7 @@ function getFailFigureForMetric(warningFigures, metricId) { return -1; } -function colourCodeResult (result, warningFigure, failFigure) { +function formatColourCodedResult (result, warningFigure, failFigure) { if (result >= failFigure) { return clc.red(result); } @@ -44,3 +54,7 @@ function colourCodeResult (result, warningFigure, failFigure) { return result; } + +function formatResult (result, warningFigure, failFigure) { + return result; +} diff --git a/lib/formatters/Warnings.js b/lib/formatters/Warnings.js index 75f850e..b193e56 100644 --- a/lib/formatters/Warnings.js +++ b/lib/formatters/Warnings.js @@ -3,28 +3,33 @@ 'use strict'; var _ = require('underscore'), - clc = require('cli-color'); + clc = require('cli-color'), + colourCodedLogo = clc.red('PA') + clc.yellow('RK') + clc.green('ER') + '-JS' + "\n", + nonColourCodedLogo = "PARKER-JS\n"; module.exports = function (metrics, results, settings) { + var reportLines = []; + // formats output as warning list - var logo = clc.red('PA') + clc.yellow('RK') + clc.green('ER') + '-JS' + "\n"; + if (settings.surpressColours) { + var logo = nonColourCodedLogo; + } else { + var logo = colourCodedLogo; + } metrics = metrics.filter(function (metric) { return settings.warningFigures.hasOwnProperty(metric.id); }); - return logo + _.reduce(metrics, function (str, metric) { - var warningFigure = getWarningFigureForMetric(settings.warningFigures, metric.id), - failFigure = getFailFigureForMetric(settings.warningFigures, metric.id); - if (results[metric.id] && results[metric.id] >= failFigure) { - return str + clc.red("Failure: " + metric.name + ": " + results[metric.id]) + '\n'; - } - else if (results[metric.id] && results[metric.id] >= warningFigure) { - return str + clc.yellow("Warning: " + metric.name + ": " + results[metric.id]) + '\n'; + _.each(metrics, function (metric) { + if (settings.surpressColours) { + reportLines.push(getWarningTextForMetric(results, settings.warningFigures, metric.id, metric.name)); + } else { + reportLines.push(getColourCodedWarningTextForMetric(results, settings.warningFigures, metric.id, metric.name)); } - - return str; }, ''); + + return logo + _.compact(reportLines).join("\n"); }; function getWarningFigureForMetric(warningFigures, metricId) { @@ -42,3 +47,31 @@ function getFailFigureForMetric(warningFigures, metricId) { return -1; } + +function getWarningTextForMetric(results, warningFigures, metricId, metricName) { + var warningFigure = getWarningFigureForMetric(warningFigures, metricId), + failFigure = getFailFigureForMetric(warningFigures, metricId); + if (results[metricId] && results[metricId] >= failFigure) { + return "Failure: " + metricName + ": " + results[metricId]; + } + else if (results[metricId] && results[metricId] >= warningFigure) { + return "Warning: " + metricName + ": " + results[metricId]; + } + + return ''; +} + +function getColourCodedWarningTextForMetric(results, warningFigures, metricId, metricName) { + var warningText = getWarningTextForMetric(results, warningFigures, metricId, metricName); + + if (warningText == '') { + return ''; + } + + if (warningText.indexOf('Warning:') >= 0) { + return clc.yellow(warningText); + } + + return clc.red(warningText); +} + diff --git a/parker.js b/parker.js index e89dcc5..2102bec 100755 --- a/parker.js +++ b/parker.js @@ -24,7 +24,12 @@ var _ = require('underscore'), async = require('async'), path = require('path'), info = require('./lib/Info'), - warningFigures = require('./data/warning-figures-default.js'); + warningFigurePresets = { + 'default': require('./data/warning-figures-default.js'), + 'strict': require('./data/warning-figures-strict.js') + }, + warningFigures = warningFigurePresets.default, + surpressColours = false; if (argv.config) { var controller = new ConfigController(); @@ -91,10 +96,19 @@ controller.on('showNumericOnly', function () { }); }); -controller.on('customWarningFigures', function (customWarningFigures) { - warningFigures = customWarningFigures; +controller.on('setWarningFigures', function (warningFigureSetting) { + if (_.isString(warningFigureSetting) && warningFigurePresets.hasOwnProperty(warningFigureSetting)) { + warningFigures = warningFigurePresets[warningFigureSetting]; + } + else if (_.isObject(warningFigures)) { + warningFigures = warningFigureSetting; + } }); +controller.on('setSurpressColours', function () { + surpressColours = true; +});; + var readDirectory = function (directoryPath, onFileLoad, onAllLoad) { fs.readdir(directoryPath, function (err, files) { async.each(files, function (file, fileDone) { @@ -123,11 +137,26 @@ var fileIsStylesheet = function (filePath) { var runReport = function (stylesheets, metrics) { var results = parker.run(stylesheets), options = { - warningFigures: warningFigures + warningFigures: warningFigures || warningFigurePresets.default, + surpressColours: surpressColours }; + console.log(formatter(metrics, results, options)); + process.exit(getExitCode(results, warningFigures)); }; +var getExitCode = function (results, warningFigures) { + var exitCode = 0; + + _.each(warningFigures, function(warningFigure, id) { + if (results[id] >= warningFigure[1]) { + exitCode = 1; + } + }); + + return exitCode; +} + if (module.parent) { module.exports = Parker; } else { diff --git a/test/CliController.js b/test/CliController.js index ab83a1a..145105a 100644 --- a/test/CliController.js +++ b/test/CliController.js @@ -81,6 +81,33 @@ describe('The CLI Controller', function() { expect(callback).to.have.been.calledWith('json'); }); + it('responds to a --warning-figures switch by dispatching a warning figures event', function () { + var callback = sinon.spy(), + cliController = new CliController(); + + cliController.on('setWarningFigures', callback); + cliController.dispatch({'warning-figures': 'strict'}); + expect(callback).to.have.been.calledWith('strict'); + }); + + it('responds to a --strict switch by dispatching a warning figures event', function () { + var callback = sinon.spy(), + cliController = new CliController(); + + cliController.on('setWarningFigures', callback); + cliController.dispatch({'strict': true}); + expect(callback).to.have.been.calledWith('strict'); + }); + + it('responds to a --surpress-colours switch by dispatching a setSurpressColours event', function () { + var callback = sinon.spy(), + cliController = new CliController(); + + cliController.on('setSurpressColours', callback); + cliController.dispatch({'surpress-colours': true}); + expect(callback).to.have.been.called; + }); + it('responds to no data supplied by dispatching a help event', function () { var callback = sinon.spy(), cliController = new CliController(); diff --git a/test/CliIntegration.js b/test/CliIntegration.js index 5e62510..86c722a 100644 --- a/test/CliIntegration.js +++ b/test/CliIntegration.js @@ -4,6 +4,23 @@ var expect = require('chai').expect exec = require('child_process').exec; describe('The Parker CLI tool', function () { + it('should load settings from a config file when invoked with a --config="" switch', function (done) { + exec('node parker.js --config="test/fixtures/minimal-config.json"', function (err, stdout, stderr) { + expect(stdout).to.not.contain('Usage:'); + expect(stdout).to.contain('Total Stylesheets'); + done(); + }); + }); + + it('should load custom warning figures when invoked with a config file containing them', function (done) { + exec('node parker.js --config="test/fixtures/config-with-warning-figures.json"', function (err, stdout, stderr) { + expect(stdout).to.not.contain('Failure: Top Selector Specificity'); + expect(stdout).to.contain('Warning: Total Unique Colours'); + expect(stdout).to.contain('Failure: Selectors Per Rule'); + done(); + }); + }); + it('should display usage information when invoked with a -h or --help switch', function (done) { exec('node parker.js -h', function (err, stdout, stderr) { expect(stdout).to.contain('Usage:'); @@ -30,7 +47,7 @@ describe('The Parker CLI tool', function () { }); it( - 'should not report results for metrics with no configured warning' + 'should not report warnings for metrics with no configured warning' + ' figure when invoked with a --format="warnings" switch', function (done) { exec('node parker.js test/fixtures/specificity-warning.css --format="warnings"', function (err, stdout, stderr) { @@ -40,19 +57,33 @@ describe('The Parker CLI tool', function () { } ); - it('should load settings from a config file when invoked with a --config="" switch', function (done) { - exec('node parker.js --config="test/fixtures/minimal-config.json"', function (err, stdout, stderr) { - expect(stdout).to.not.contain('Usage:'); - expect(stdout).to.contain('Total Stylesheets'); + it('should reduce the threashold at which warnings are reported when invoked with a --warning-figures="strict" switch', function (done) { + exec('node parker.js test/fixtures/one-id-selector.css --format="warnings"', function (defaultErr, defaultStdout, defaultStderr) { + exec('node parker.js test/fixtures/one-id-selector.css --format="warnings" --warning-figures="strict"', function (strictErr, strictStdout, strictStderr) { + expect(defaultStdout).to.not.contain('Failure: Top Selector Specificity'); + expect(strictStdout).to.contain('Failure: Top Selector Specificity'); + done(); + }); + }); + }); + + it('should surpress all colour coding when invoked with a --surpress-colours switch', function (done) { + exec('node parker.js test/fixtures/specificity-warning.css --surpress-colours', function (err, stdout, stderr) { + expect(stdout).to.not.contain('[31m'); done(); }); }); - it('should load custom warning figures when invoked with a config file containing them', function (done) { - exec('node parker.js --config="test/fixtures/config-with-warning-figures.json"', function (err, stdout, stderr) { - expect(stdout).to.not.contain('Failure: Top Selector Specificity'); - expect(stdout).to.contain('Warning: Total Unique Colours'); - expect(stdout).to.contain('Failure: Selectors Per Rule'); + it('should surpress all colour coding when invoked with a --surpress-colours switch and a --format="warnings" switch', function (done) { + exec('node parker.js test/fixtures/specificity-warning.css --surpress-colours --format="warnings"', function (err, stdout, stderr) { + expect(stdout).to.not.contain('[31m'); + done(); + }); + }); + + it('should exit with code 1 when a failure is reported', function (done) { + exec('node parker.js test/fixtures/specificity-warning.css --format="warnings"', function (err, stdout, stderr) { + expect(err.code).to.be.above(0); done(); }); }); diff --git a/test/ConfigController.js b/test/ConfigController.js index cf7d4e6..7b949bf 100644 --- a/test/ConfigController.js +++ b/test/ConfigController.js @@ -43,8 +43,19 @@ describe('The Config Controller', function() { warningFigures = {'top-selector-specificity': [50, 99]}, configController = new ConfigController(); - configController.on('customWarningFigures', callback); + configController.on('setWarningFigures', callback); configController.dispatch({'warning-figures': warningFigures}); expect(callback).to.have.been.calledWith(warningFigures); }); + + it('responds to a "surpress-colours" setting by dispatching a surpress colours event', function () { + var callback = sinon.spy(), + configController = new ConfigController(); + + configController.on('setSurpressColours', callback); + configController.dispatch({'surpress-colours': true}); + expect(callback).to.have.been.called; + }); + + }); diff --git a/test/fixtures/one-id-selector.css b/test/fixtures/one-id-selector.css new file mode 100644 index 0000000..d1f8038 --- /dev/null +++ b/test/fixtures/one-id-selector.css @@ -0,0 +1,3 @@ +#nav { + border: 0; +} From a68faf30eec87a8df2cec4b2835e09424eecc587 Mon Sep 17 00:00:00 2001 From: Katie Fenn Date: Sun, 31 Aug 2014 11:28:17 +0100 Subject: [PATCH 06/15] Increment version number --- lib/CliController.js | 2 +- lib/CliFormatter.js | 2 +- lib/ConfigController.js | 2 +- lib/CssDeclaration.js | 4 ++-- lib/CssMediaQuery.js | 2 +- lib/CssRule.js | 2 +- lib/CssSelector.js | 4 ++-- lib/CssStylesheet.js | 2 +- lib/Info.js | 2 +- lib/Parker.js | 2 +- lib/formatters/Csv.js | 2 +- lib/formatters/Human.js | 2 +- lib/formatters/Json.js | 2 +- lib/formatters/Warnings.js | 2 +- metrics/All.js | 2 +- metrics/IdentifiersPerSelector.js | 4 ++-- metrics/MediaQueries.js | 4 ++-- metrics/SelectorsPerRule.js | 4 ++-- metrics/SpecificityPerSelector.js | 2 +- metrics/TopSelectorSpecificity.js | 4 ++-- metrics/TopSelectorSpecificitySelector.js | 4 ++-- metrics/TotalDeclarations.js | 4 ++-- metrics/TotalIdSelectors.js | 3 +-- metrics/TotalIdentifiers.js | 4 ++-- metrics/TotalImportantKeywords.js | 2 +- metrics/TotalMediaQueries.js | 4 ++-- metrics/TotalRules.js | 4 ++-- metrics/TotalSelectors.js | 4 ++-- metrics/TotalStylesheetSize.js | 4 ++-- metrics/TotalStylesheets.js | 4 ++-- metrics/TotalUniqueColours.js | 2 +- metrics/UniqueColours.js | 2 +- package.json | 2 +- parker.js | 2 +- test/CliController.js | 2 +- test/CliIntegration.js | 2 +- test/ConfigController.js | 2 +- test/CssDeclaration.js | 4 ++-- test/CssMediaQuery.js | 4 ++-- test/CssRule.js | 2 +- test/CssSelector.js | 4 ++-- test/CssStylesheet.js | 4 ++-- test/IdentifiersPerSelector.js | 2 +- test/Parker.js | 2 +- 44 files changed, 62 insertions(+), 63 deletions(-) diff --git a/lib/CliController.js b/lib/CliController.js index d9e8454..871ecb9 100644 --- a/lib/CliController.js +++ b/lib/CliController.js @@ -1,4 +1,4 @@ -/*! Parker v0.0.0 - MIT license */ +/*! Parker v0.1.0 - MIT license */ 'use strict'; diff --git a/lib/CliFormatter.js b/lib/CliFormatter.js index 354442e..6e9cb74 100644 --- a/lib/CliFormatter.js +++ b/lib/CliFormatter.js @@ -1,4 +1,4 @@ -/*! Parker v0.0.0 - MIT license */ +/*! Parker v0.1.0 - MIT license */ 'use strict'; diff --git a/lib/ConfigController.js b/lib/ConfigController.js index ee450f8..9db618f 100644 --- a/lib/ConfigController.js +++ b/lib/ConfigController.js @@ -1,4 +1,4 @@ -/*! Parker v0.0.0 - MIT license */ +/*! Parker v0.1.0 - MIT license */ 'use strict'; diff --git a/lib/CssDeclaration.js b/lib/CssDeclaration.js index eebe7d6..772aa77 100644 --- a/lib/CssDeclaration.js +++ b/lib/CssDeclaration.js @@ -1,4 +1,4 @@ -/*! Parker v0.0.0 - MIT license */ +/*! Parker v0.1.0 - MIT license */ 'use strict'; @@ -23,4 +23,4 @@ CssDeclaration.prototype.getValue = function () { return this.raw.split(':')[1].trim(); }; -module.exports = CssDeclaration; \ No newline at end of file +module.exports = CssDeclaration; diff --git a/lib/CssMediaQuery.js b/lib/CssMediaQuery.js index 5391315..0cdd3a3 100644 --- a/lib/CssMediaQuery.js +++ b/lib/CssMediaQuery.js @@ -1,4 +1,4 @@ -/*! Parker v0.0.0 - MIT license */ +/*! Parker v0.1.0 - MIT license */ 'use strict'; diff --git a/lib/CssRule.js b/lib/CssRule.js index 1f9c183..4e1d6fa 100644 --- a/lib/CssRule.js +++ b/lib/CssRule.js @@ -1,4 +1,4 @@ -/*! Parker v0.0.0 - MIT license */ +/*! Parker v0.1.0 - MIT license */ 'use strict'; diff --git a/lib/CssSelector.js b/lib/CssSelector.js index baee4e1..fb87061 100644 --- a/lib/CssSelector.js +++ b/lib/CssSelector.js @@ -1,4 +1,4 @@ -/*! Parker v0.0.0 - MIT license */ +/*! Parker v0.1.0 - MIT license */ 'use strict'; @@ -19,4 +19,4 @@ CssSelector.prototype.getIdentifiers = function () { return identifiers; }; -module.exports = CssSelector; \ No newline at end of file +module.exports = CssSelector; diff --git a/lib/CssStylesheet.js b/lib/CssStylesheet.js index 6c8bbdf..f68e2ad 100644 --- a/lib/CssStylesheet.js +++ b/lib/CssStylesheet.js @@ -1,4 +1,4 @@ -/*! Parker v0.0.0 - MIT license */ +/*! Parker v0.1.0 - MIT license */ 'use strict'; diff --git a/lib/Info.js b/lib/Info.js index 56adbbe..8b71a4c 100644 --- a/lib/Info.js +++ b/lib/Info.js @@ -1,4 +1,4 @@ -/*! Parker v0.0.0 - MIT license */ +/*! Parker v0.1.0 - MIT license */ 'use strict'; diff --git a/lib/Parker.js b/lib/Parker.js index 60ea748..60c7f42 100644 --- a/lib/Parker.js +++ b/lib/Parker.js @@ -1,4 +1,4 @@ -/*! Parker v0.0.0 - MIT license */ +/*! Parker v0.1.0 - MIT license */ 'use strict'; diff --git a/lib/formatters/Csv.js b/lib/formatters/Csv.js index 4d2f3dc..dfb4295 100644 --- a/lib/formatters/Csv.js +++ b/lib/formatters/Csv.js @@ -1,4 +1,4 @@ -/*! Parker v0.0.0 - MIT license */ +/*! Parker v0.1.0 - MIT license */ 'use strict'; diff --git a/lib/formatters/Human.js b/lib/formatters/Human.js index 24102c2..930b6dd 100644 --- a/lib/formatters/Human.js +++ b/lib/formatters/Human.js @@ -1,4 +1,4 @@ -/*! Parker v0.0.0 - MIT license */ +/*! Parker v0.1.0 - MIT license */ 'use strict'; diff --git a/lib/formatters/Json.js b/lib/formatters/Json.js index 8a744f5..9773675 100644 --- a/lib/formatters/Json.js +++ b/lib/formatters/Json.js @@ -1,4 +1,4 @@ -/*! Parker v0.0.0 - MIT license */ +/*! Parker v0.1.0 - MIT license */ 'use strict'; diff --git a/lib/formatters/Warnings.js b/lib/formatters/Warnings.js index b193e56..d70b163 100644 --- a/lib/formatters/Warnings.js +++ b/lib/formatters/Warnings.js @@ -1,4 +1,4 @@ -/*! Parker v0.0.0 - MIT license */ +/*! Parker v0.1.0 - MIT license */ 'use strict'; diff --git a/metrics/All.js b/metrics/All.js index c36b3e2..06a995c 100644 --- a/metrics/All.js +++ b/metrics/All.js @@ -1,4 +1,4 @@ -/*! Parker v0.0.0 - MIT license */ +/*! Parker v0.1.0 - MIT license */ 'use strict'; diff --git a/metrics/IdentifiersPerSelector.js b/metrics/IdentifiersPerSelector.js index 256ed39..55a6b97 100644 --- a/metrics/IdentifiersPerSelector.js +++ b/metrics/IdentifiersPerSelector.js @@ -1,4 +1,4 @@ -/*! Parker v0.0.0 - MIT license */ +/*! Parker v0.1.0 - MIT license */ 'use strict'; @@ -30,4 +30,4 @@ var getIdentifiers = function (selector) { }); return identifiers; -}; \ No newline at end of file +}; diff --git a/metrics/MediaQueries.js b/metrics/MediaQueries.js index 6256298..e7edead 100644 --- a/metrics/MediaQueries.js +++ b/metrics/MediaQueries.js @@ -1,4 +1,4 @@ -/*! Parker v0.0.0 - MIT license */ +/*! Parker v0.1.0 - MIT license */ 'use strict'; @@ -16,4 +16,4 @@ module.exports = { filter: function (value, index, self) { return self.indexOf(value) === index; } -}; \ No newline at end of file +}; diff --git a/metrics/SelectorsPerRule.js b/metrics/SelectorsPerRule.js index dcd1975..9accff5 100644 --- a/metrics/SelectorsPerRule.js +++ b/metrics/SelectorsPerRule.js @@ -1,4 +1,4 @@ -/*! Parker v0.0.0 - MIT license */ +/*! Parker v0.1.0 - MIT license */ 'use strict'; @@ -27,4 +27,4 @@ var getSelectors = function (selectorBlock) { }); return trimmedSelectors; -}; \ No newline at end of file +}; diff --git a/metrics/SpecificityPerSelector.js b/metrics/SpecificityPerSelector.js index 859f9e6..3558a2c 100644 --- a/metrics/SpecificityPerSelector.js +++ b/metrics/SpecificityPerSelector.js @@ -1,4 +1,4 @@ -/*! Parker v0.0.0 - MIT license */ +/*! Parker v0.1.0 - MIT license */ 'use strict'; diff --git a/metrics/TopSelectorSpecificity.js b/metrics/TopSelectorSpecificity.js index 9c0dcae..09685e5 100644 --- a/metrics/TopSelectorSpecificity.js +++ b/metrics/TopSelectorSpecificity.js @@ -1,4 +1,4 @@ -/*! Parker v0.0.0 - MIT license */ +/*! Parker v0.1.0 - MIT license */ 'use strict'; @@ -118,4 +118,4 @@ var countPseudoElementIdentifiers = function (identifier) { } return 0; -}; \ No newline at end of file +}; diff --git a/metrics/TopSelectorSpecificitySelector.js b/metrics/TopSelectorSpecificitySelector.js index 862f54d..f5afd3d 100644 --- a/metrics/TopSelectorSpecificitySelector.js +++ b/metrics/TopSelectorSpecificitySelector.js @@ -1,4 +1,4 @@ -/*! Parker v0.0.0 - MIT license */ +/*! Parker v0.1.0 - MIT license */ 'use strict'; @@ -121,4 +121,4 @@ var countPseudoElementIdentifiers = function (identifier) { } return 0; -}; \ No newline at end of file +}; diff --git a/metrics/TotalDeclarations.js b/metrics/TotalDeclarations.js index 4a234c9..665564d 100644 --- a/metrics/TotalDeclarations.js +++ b/metrics/TotalDeclarations.js @@ -1,4 +1,4 @@ -/*! Parker v0.0.0 - MIT license */ +/*! Parker v0.1.0 - MIT license */ 'use strict'; @@ -11,4 +11,4 @@ module.exports = { measure: function (declaration) { return 1; } -}; \ No newline at end of file +}; diff --git a/metrics/TotalIdSelectors.js b/metrics/TotalIdSelectors.js index 135d299..d44fee0 100644 --- a/metrics/TotalIdSelectors.js +++ b/metrics/TotalIdSelectors.js @@ -1,5 +1,4 @@ - -/*! Parker v0.0.0 - MIT license */ +/*! Parker v0.1.0 - MIT license */ 'use strict'; diff --git a/metrics/TotalIdentifiers.js b/metrics/TotalIdentifiers.js index c8e7ac2..d3941cf 100644 --- a/metrics/TotalIdentifiers.js +++ b/metrics/TotalIdentifiers.js @@ -1,4 +1,4 @@ -/*! Parker v0.0.0 - MIT license */ +/*! Parker v0.1.0 - MIT license */ 'use strict'; @@ -13,4 +13,4 @@ module.exports = { measure: function (identifier) { return 1; } -}; \ No newline at end of file +}; diff --git a/metrics/TotalImportantKeywords.js b/metrics/TotalImportantKeywords.js index 4281b7c..f56a521 100644 --- a/metrics/TotalImportantKeywords.js +++ b/metrics/TotalImportantKeywords.js @@ -1,4 +1,4 @@ -/*! Parker v0.0.0 - MIT license */ +/*! Parker v0.1.0 - MIT license */ 'use strict'; diff --git a/metrics/TotalMediaQueries.js b/metrics/TotalMediaQueries.js index 2ba1ba5..7360a79 100644 --- a/metrics/TotalMediaQueries.js +++ b/metrics/TotalMediaQueries.js @@ -1,4 +1,4 @@ -/*! Parker v0.0.0 - MIT license */ +/*! Parker v0.1.0 - MIT license */ 'use strict'; @@ -16,4 +16,4 @@ module.exports = { filter: function (value, index, self) { return self.indexOf(value) === index; } -}; \ No newline at end of file +}; diff --git a/metrics/TotalRules.js b/metrics/TotalRules.js index d0de0f9..a00461e 100644 --- a/metrics/TotalRules.js +++ b/metrics/TotalRules.js @@ -1,4 +1,4 @@ -/*! Parker v0.0.0 - MIT license */ +/*! Parker v0.1.0 - MIT license */ 'use strict'; @@ -11,4 +11,4 @@ module.exports = { measure: function (rule) { return 1; } -}; \ No newline at end of file +}; diff --git a/metrics/TotalSelectors.js b/metrics/TotalSelectors.js index cc44604..5355276 100644 --- a/metrics/TotalSelectors.js +++ b/metrics/TotalSelectors.js @@ -1,4 +1,4 @@ -/*! Parker v0.0.0 - MIT license */ +/*! Parker v0.1.0 - MIT license */ 'use strict'; @@ -13,4 +13,4 @@ module.exports = { measure: function (selector) { return 1; } -}; \ No newline at end of file +}; diff --git a/metrics/TotalStylesheetSize.js b/metrics/TotalStylesheetSize.js index 4853617..80c3ad6 100644 --- a/metrics/TotalStylesheetSize.js +++ b/metrics/TotalStylesheetSize.js @@ -1,4 +1,4 @@ -/*! Parker v0.0.0 - MIT license */ +/*! Parker v0.1.0 - MIT license */ 'use strict'; @@ -15,4 +15,4 @@ module.exports = { function byteCount(s) { return encodeURI(s).split(/%..|./).length - 1; -} \ No newline at end of file +} diff --git a/metrics/TotalStylesheets.js b/metrics/TotalStylesheets.js index 8b2f223..58f953b 100644 --- a/metrics/TotalStylesheets.js +++ b/metrics/TotalStylesheets.js @@ -1,4 +1,4 @@ -/*! Parker v0.0.0 - MIT license */ +/*! Parker v0.1.0 - MIT license */ 'use strict'; @@ -11,4 +11,4 @@ module.exports = { measure: function (stylesheet) { return 1; } -}; \ No newline at end of file +}; diff --git a/metrics/TotalUniqueColours.js b/metrics/TotalUniqueColours.js index 6d70ad8..4451c14 100644 --- a/metrics/TotalUniqueColours.js +++ b/metrics/TotalUniqueColours.js @@ -1,4 +1,4 @@ -/*! Parker v0.0.0 - MIT license */ +/*! Parker v0.1.0 - MIT license */ 'use strict'; diff --git a/metrics/UniqueColours.js b/metrics/UniqueColours.js index b309af0..456a57e 100644 --- a/metrics/UniqueColours.js +++ b/metrics/UniqueColours.js @@ -1,4 +1,4 @@ -/*! Parker v0.0.0 - MIT license */ +/*! Parker v0.1.0 - MIT license */ 'use strict'; diff --git a/package.json b/package.json index 2976a79..13508e2 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "parker", "description": "Stylesheet analysis tool for CSS", "keywords": ["css","stylesheet","analysis"], - "version": "0.0.8", + "version": "0.1.0", "main": "parker.js", "dependencies": { "underscore": "*", diff --git a/parker.js b/parker.js index 2102bec..4026e50 100755 --- a/parker.js +++ b/parker.js @@ -1,6 +1,6 @@ #!/usr/bin/env node -/*! csstool v0.0.0 - MIT license */ +/*! Parker v0.1.0 - MIT license */ 'use strict'; diff --git a/test/CliController.js b/test/CliController.js index 145105a..5eb0c71 100644 --- a/test/CliController.js +++ b/test/CliController.js @@ -1,4 +1,4 @@ -/*! Parker v0.0.0 - MIT license */ +/*! Parker v0.1.0 - MIT license */ var chai = require('chai'), expect = require('chai').expect, diff --git a/test/CliIntegration.js b/test/CliIntegration.js index 86c722a..051b50c 100644 --- a/test/CliIntegration.js +++ b/test/CliIntegration.js @@ -1,4 +1,4 @@ -/*! Parker v0.0.0 - MIT license */ +/*! Parker v0.1.0 - MIT license */ var expect = require('chai').expect exec = require('child_process').exec; diff --git a/test/ConfigController.js b/test/ConfigController.js index 7b949bf..a69ed82 100644 --- a/test/ConfigController.js +++ b/test/ConfigController.js @@ -1,4 +1,4 @@ -/*! Parker v0.0.0 - MIT license */ +/*! Parker v0.1.0 - MIT license */ var chai = require('chai'), expect = require('chai').expect, diff --git a/test/CssDeclaration.js b/test/CssDeclaration.js index 52263a1..c09d1ea 100644 --- a/test/CssDeclaration.js +++ b/test/CssDeclaration.js @@ -1,4 +1,4 @@ -/*! Parker v0.0.0 - MIT license */ +/*! Parker v0.1.0 - MIT license */ var expect = require('chai').expect, CssDeclaration = require('../lib/CssDeclaration.js'); @@ -12,4 +12,4 @@ describe('The Declaration Parser', function() { expect(cssDeclaration.getProperty()).to.equal('color'); expect(cssDeclaration.getValue()).to.equal('#fff'); }); -}); \ No newline at end of file +}); diff --git a/test/CssMediaQuery.js b/test/CssMediaQuery.js index db07aae..48ed81c 100644 --- a/test/CssMediaQuery.js +++ b/test/CssMediaQuery.js @@ -1,4 +1,4 @@ -/*! Parker v0.0.0 - MIT license */ +/*! Parker v0.1.0 - MIT license */ var expect = require('chai').expect, CssMediaQuery = require('../lib/CssMediaQuery.js'); @@ -25,4 +25,4 @@ describe('The Css Media Query object', function () { expect(cssMediaQuery.getRules()[0]).to.equal('a {color: #000;}'); expect(cssMediaQuery.getRules()[1]).to.equal('header {display: none;}'); }); -}); \ No newline at end of file +}); diff --git a/test/CssRule.js b/test/CssRule.js index f3be788..4cb287e 100644 --- a/test/CssRule.js +++ b/test/CssRule.js @@ -1,4 +1,4 @@ -/*! Parker v0.0.0 - MIT license */ +/*! Parker v0.1.0 - MIT license */ var expect = require('chai').expect, CssRule = require('../lib/CssRule.js'); diff --git a/test/CssSelector.js b/test/CssSelector.js index f39f410..fa7ae23 100644 --- a/test/CssSelector.js +++ b/test/CssSelector.js @@ -1,4 +1,4 @@ -/*! Parker v0.0.0 - MIT license */ +/*! Parker v0.1.0 - MIT license */ var expect = require('chai').expect, CssSelector = require('../lib/CssSelector.js'); @@ -55,4 +55,4 @@ describe('The Selector Parser', function() { var cssSelector = new CssSelector('p::first-line'); expect(cssSelector.getIdentifiers()).to.have.length(2); }); -}); \ No newline at end of file +}); diff --git a/test/CssStylesheet.js b/test/CssStylesheet.js index 85787ed..7d8e7b0 100644 --- a/test/CssStylesheet.js +++ b/test/CssStylesheet.js @@ -1,4 +1,4 @@ -/*! Parker v0.0.0 - MIT license */ +/*! Parker v0.1.0 - MIT license */ var expect = require('chai').expect, CssStylesheet = require('../lib/CssStylesheet.js'); @@ -66,4 +66,4 @@ describe('The Stylesheet Parser', function() { expect(cssStylesheet.getMalformedStatements()[0]).to.equal('h1;'); expect(cssStylesheet.getMalformedStatements()[1]).to.equal('{font-weight: bold;}'); }); -}); \ No newline at end of file +}); diff --git a/test/IdentifiersPerSelector.js b/test/IdentifiersPerSelector.js index 539d6a7..f142bab 100644 --- a/test/IdentifiersPerSelector.js +++ b/test/IdentifiersPerSelector.js @@ -1,4 +1,4 @@ -/*! Parker v0.0.0 - MIT license */ +/*! Parker v0.1.0 - MIT license */ var expect = require('chai').expect, metric = require('../metrics/IdentifiersPerSelector.js'); diff --git a/test/Parker.js b/test/Parker.js index 7f903ff..5a9bd99 100644 --- a/test/Parker.js +++ b/test/Parker.js @@ -1,4 +1,4 @@ -/*! Parker v0.0.0 - MIT license */ +/*! Parker v0.1.0 - MIT license */ var expect = require('chai').expect, Parker = require('../lib/Parker.js'); From 6f0bd69bf2adc695cfd0906b4bc1c396fdedecca Mon Sep 17 00:00:00 2001 From: Katie Fenn Date: Sun, 31 Aug 2014 11:35:57 +0100 Subject: [PATCH 07/15] Fixing code style violations --- lib/formatters/Human.js | 9 ++++----- lib/formatters/Warnings.js | 9 ++++----- parker.js | 9 +++++---- 3 files changed, 13 insertions(+), 14 deletions(-) diff --git a/lib/formatters/Human.js b/lib/formatters/Human.js index 930b6dd..0b45d9d 100644 --- a/lib/formatters/Human.js +++ b/lib/formatters/Human.js @@ -9,13 +9,12 @@ var _ = require('underscore'), module.exports = function (metrics, results, settings) { // formats output as human-friendly text + var resultFormatter = formatColourCodedResult, + logo = colourCodedLogo; if (settings.surpressColours) { - var resultFormatter = formatResult, - logo = nonColourCodedLogo; - } else { - var resultFormatter = formatColourCodedResult, - logo = colourCodedLogo; + resultFormatter = formatResult; + logo = nonColourCodedLogo; } return logo + _.reduce(metrics, function (str, metric) { diff --git a/lib/formatters/Warnings.js b/lib/formatters/Warnings.js index d70b163..0c38bc1 100644 --- a/lib/formatters/Warnings.js +++ b/lib/formatters/Warnings.js @@ -8,13 +8,12 @@ var _ = require('underscore'), nonColourCodedLogo = "PARKER-JS\n"; module.exports = function (metrics, results, settings) { - var reportLines = []; + var reportLines = [], + logo = colourCodedLogo; // formats output as warning list if (settings.surpressColours) { - var logo = nonColourCodedLogo; - } else { - var logo = colourCodedLogo; + logo = nonColourCodedLogo; } metrics = metrics.filter(function (metric) { @@ -64,7 +63,7 @@ function getWarningTextForMetric(results, warningFigures, metricId, metricName) function getColourCodedWarningTextForMetric(results, warningFigures, metricId, metricName) { var warningText = getWarningTextForMetric(results, warningFigures, metricId, metricName); - if (warningText == '') { + if (warningText === '') { return ''; } diff --git a/parker.js b/parker.js index 4026e50..383dbfb 100755 --- a/parker.js +++ b/parker.js @@ -92,7 +92,7 @@ controller.on('setFormat', function (format) { controller.on('showNumericOnly', function () { metrics = _.filter(metrics, function (metric) { - return metric.format == 'number'; + return metric.format === 'number'; }); }); @@ -107,7 +107,7 @@ controller.on('setWarningFigures', function (warningFigureSetting) { controller.on('setSurpressColours', function () { surpressColours = true; -});; +}); var readDirectory = function (directoryPath, onFileLoad, onAllLoad) { fs.readdir(directoryPath, function (err, files) { @@ -155,13 +155,14 @@ var getExitCode = function (results, warningFigures) { }); return exitCode; -} +}; if (module.parent) { module.exports = Parker; } else { var parker = new Parker(metrics), - formatter = formatters['human']; + formatter = formatters.human; + if (argv.config) { readFile(argv.config, function (err, filedata) { controller.dispatch(JSON.parse(filedata)); From f4b355dbc4747fb11cedf4e1e9c661abd2bd1995 Mon Sep 17 00:00:00 2001 From: leny Date: Mon, 15 Sep 2014 02:13:46 +0200 Subject: [PATCH 08/15] Add tests for DeclarationsPerRule metric --- test/DeclarationsPerRule.js | 52 +++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) create mode 100644 test/DeclarationsPerRule.js diff --git a/test/DeclarationsPerRule.js b/test/DeclarationsPerRule.js new file mode 100644 index 0000000..9a7d1bf --- /dev/null +++ b/test/DeclarationsPerRule.js @@ -0,0 +1,52 @@ +/*! Parker v0.0.0 - MIT license */ + +var expect = require('chai').expect, + Parker = require('../lib/Parker.js'), + metric = require('../metrics/DeclarationsPerRule.js'); + + +describe('The declarations-per-rule metric', function () { + it('should provide a string identifier for the metric', function() { + expect(metric.id).to.be.a('string'); + }); + + it('should provide a metric type', function() { + expect(metric.aggregate).to.match(/sum|mean/g); + }); + + it('should return 0 for an empty string', function () { + expect(metric.measure('')).to.equal(0); + }); + + it('should return 1 for the selector "body {color:blue;}"', function() { + expect(metric.measure('body {color:blue;}')).to.equal(1); + }); + + it('should return 2 for the selector "body section {color:blue;background:yellow;}"', function() { + expect(metric.measure('body section {color:blue;background:yellow;}')).to.equal(2); + }); + + it('should return 2 for the selector "body section {color:blue;background:yellow;} body article h3 {text-align:center;color:red;}"', function() { + var parker = new Parker([metric]), + report = parker.run('body section {color:blue;background:yellow;} body article h3 {text-align:center;color:red;}'); + + expect(report).to.have.property('declarations-per-rule'); + expect(report['declarations-per-rule']).to.equal(2); + }); + + it('should return 1.5 for the selector "body section {color:blue;background:yellow;} body article h3 {text-align:center;}"', function() { + var parker = new Parker([metric]), + report = parker.run('body section {color:blue;background:yellow;} body article h3 {text-align:center;}'); + + expect(report).to.have.property('declarations-per-rule'); + expect(report['declarations-per-rule']).to.equal(1.5); + }); + + it('should return 2 for the selector "body section {-webkit-something:blue;-moz-anything:yellow;} body article h3 {text-align:center;color:red;}"', function() { + var parker = new Parker([metric]), + report = parker.run('body section {-webkit-something:blue;-moz-anything:yellow;} body article h3 {text-align:center;color:red;}'); + + expect(report).to.have.property('declarations-per-rule'); + expect(report['declarations-per-rule']).to.equal(2); + }); +}); From fe02fb74f1f6c2276c08186256b85ecff033bf5a Mon Sep 17 00:00:00 2001 From: leny Date: Mon, 15 Sep 2014 02:14:39 +0200 Subject: [PATCH 09/15] Add DeclarationsPerRule metric --- metrics/DeclarationsPerRule.js | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 metrics/DeclarationsPerRule.js diff --git a/metrics/DeclarationsPerRule.js b/metrics/DeclarationsPerRule.js new file mode 100644 index 0000000..3ebbd6c --- /dev/null +++ b/metrics/DeclarationsPerRule.js @@ -0,0 +1,17 @@ +/*! Parker v0.0.0 - MIT license */ + +'use strict'; + +var CssRule = require( "../lib/CssRule.js" ); + +module.exports = { + id: 'declarations-per-rule', + name: 'Declarations Per Rule', + type: 'rule', + aggregate: 'mean', + format: 'number', + measure: function (rule) { + console.log(rule); + return (new CssRule(rule)).getDeclarations().length; + } +}; From 1e235fe7e8958efa610958c5206767349a19ac6b Mon Sep 17 00:00:00 2001 From: leny Date: Mon, 15 Sep 2014 02:15:05 +0200 Subject: [PATCH 10/15] Reference DeclarationsPerRule metric in All metric --- metrics/All.js | 1 + 1 file changed, 1 insertion(+) diff --git a/metrics/All.js b/metrics/All.js index 06a995c..8d15702 100644 --- a/metrics/All.js +++ b/metrics/All.js @@ -15,6 +15,7 @@ module.exports = [ // Stylesheet Element Averages require('./SelectorsPerRule.js'), + require('./DeclarationsPerRule.js'), require('./IdentifiersPerSelector.js'), // Specificity From 16103bc9937ab609d3d84b242a7e1fff8c9223fd Mon Sep 17 00:00:00 2001 From: leny Date: Mon, 15 Sep 2014 02:15:26 +0200 Subject: [PATCH 11/15] Add missing anchors in documentation --- docs/metrics/readme.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/metrics/readme.md b/docs/metrics/readme.md index cbe7fad..7049d81 100644 --- a/docs/metrics/readme.md +++ b/docs/metrics/readme.md @@ -78,7 +78,7 @@ Measures the total number of rules. Each rule defines a specific behaviour of th - __aggregate__: sum - __format__: number - + #### Total Selectors Measures the total number of selectors. Each selector defines a group of elements affected by the design. Stylesheets with fewer selectors are simpler. @@ -108,6 +108,7 @@ Measures the total number of property declarations. Each property declaration de - __aggregate__: sum - __format__: number + #### Selectors Per Rule Measures the average number of selectors in every rule. Stylesheet rules can be applied to several groups of elements using multiple selectors, separated by a comma. Fewer selectors in a rule makes its properties specific to a smaller group of elements, and also makes a rule easier to read in text editors and developer tools. @@ -117,6 +118,7 @@ Measures the average number of selectors in every rule. Stylesheet rules can be - __aggregate__: sum - __format__: number + #### Identifiers Per Selector Measures the average number of identifiers in every selector. Selectors can be made more specific to combinations of elements by adding more identifiers to a selector. Fewer identifiers in a given selector reduces its dependency on certain DOM structures, allowing more changes to your HTML before being forced to change your CSS. Selectors with fewer identifiers are also more readable. From 0a7e67d22a0fc481e24a17b5507c7283337d0311 Mon Sep 17 00:00:00 2001 From: leny Date: Mon, 15 Sep 2014 02:15:51 +0200 Subject: [PATCH 12/15] Add documentation for DeclarationsPerRule metric --- docs/metrics/readme.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/docs/metrics/readme.md b/docs/metrics/readme.md index 7049d81..5b3671e 100644 --- a/docs/metrics/readme.md +++ b/docs/metrics/readme.md @@ -12,6 +12,7 @@ Parker has a suite of metrics that are useful for measuring stylesheets. What fo 4. [Total Declarations](#total-declarations) 5. [Selectors Per Rule](#selectors-per-rule) 6. [Identifiers Per Selectors](#identifiers-per-selector) + 7. [Declarations Per Rule](#declarations-per-rule) 3. [Specificity](#specificity) 1. [Specificity Per Selector](#specificity-per-selector) 2. [Top Selector Specificity](#top-selector-specificity) @@ -128,6 +129,16 @@ Measures the average number of identifiers in every selector. Selectors can be m - __aggregate__: mean - __format__: number + +#### Declarations Per Rule +Measures the average number of declarations in every rule. Rules with fewer property declarations are simpler, and also makes rules easier to read in text editors and developer tools. + +- __id__: declarations-per-rule +- __name__: Declarations Per Rule +- __type__: rule +- __aggregate__: mean +- __format__: number + ### Specificity A rule can be overrided by another rule with a more specific selector. Complexity is added to stylesheets when multiple levels of cascading rules are used in stylesheets, because it becomes more difficult to predict which properties apply to a given element without keeping in mind other rules. From 94374b3ed2641b120e44f55f7f77ef81a11daa67 Mon Sep 17 00:00:00 2001 From: leny Date: Mon, 15 Sep 2014 02:24:55 +0200 Subject: [PATCH 13/15] Removing dumb console.log --- metrics/DeclarationsPerRule.js | 1 - 1 file changed, 1 deletion(-) diff --git a/metrics/DeclarationsPerRule.js b/metrics/DeclarationsPerRule.js index 3ebbd6c..1d26764 100644 --- a/metrics/DeclarationsPerRule.js +++ b/metrics/DeclarationsPerRule.js @@ -11,7 +11,6 @@ module.exports = { aggregate: 'mean', format: 'number', measure: function (rule) { - console.log(rule); return (new CssRule(rule)).getDeclarations().length; } }; From e3132767159a2d7b188a646ad39d0db3e94addc3 Mon Sep 17 00:00:00 2001 From: Katie Fenn Date: Sun, 4 Jan 2015 00:17:22 +0000 Subject: [PATCH 14/15] Replaced CssSelector regexes with a parser, fixed specificity bug --- lib/CssSelector.js | 43 ++++++++++++++++++++++++++----- metrics/TopSelectorSpecificity.js | 35 +++++++++++++------------ test/CssSelector.js | 2 +- test/TopSelectorSpecificity.js | 32 +++++++++++++++++++++++ 4 files changed, 87 insertions(+), 25 deletions(-) diff --git a/lib/CssSelector.js b/lib/CssSelector.js index fb87061..b55404b 100644 --- a/lib/CssSelector.js +++ b/lib/CssSelector.js @@ -2,21 +2,50 @@ 'use strict'; -var _ = require('underscore'); +var _ = require('underscore'), + DELIMITERS = ['.', '#', '>', '[', ' ', ':', '*']; function CssSelector(raw) { this.raw = raw; + this.identifiers = []; } CssSelector.prototype.getIdentifiers = function () { - var identifiers = [], - segments = this.raw.split(/\s+[\s\+>]\s?|~^=/g); + var identifier = '', + bracketDepth = 0, + parenDepth = 0; - _.each(segments, function (segment) { - identifiers = identifiers.concat(segment.match(/[#\.:]?[\w\-\*]+|\[[\w=\-~'"\|]+\]|:{2}[\w-]+/g)); - }); + _.each(this.raw, function (character, index) { + var insideBrackets = bracketDepth || parenDepth, + isSecondColon = character == ':' && this.raw[index - 1] == ':'; - return identifiers; + if (!insideBrackets && isDelimiter(character) && !isSecondColon) { + this.addIdentifier(identifier); + identifier = ''; + } + + switch(character) { + case '(': parenDepth++; break; + case ')': parenDepth--; break; + case '[': bracketDepth++; break; + case ']': bracketDepth--; break; + } + + if (!_.contains([' ', '>'], character)) { + identifier += character; + } + }, this); + + this.addIdentifier(identifier); + return _.without(this.identifiers, ' ', ''); +} + +CssSelector.prototype.addIdentifier = function (identifier) { + this.identifiers.push(identifier); }; +function isDelimiter(character) { + return _.contains(DELIMITERS, character) +} + module.exports = CssSelector; diff --git a/metrics/TopSelectorSpecificity.js b/metrics/TopSelectorSpecificity.js index 09685e5..3d902b8 100644 --- a/metrics/TopSelectorSpecificity.js +++ b/metrics/TopSelectorSpecificity.js @@ -2,7 +2,8 @@ 'use strict'; -var _ = require('underscore'); +var _ = require('underscore'), + CssSelector = require('../lib/CssSelector'); module.exports = { id: 'top-selector-specificity', @@ -10,11 +11,14 @@ module.exports = { type: 'selector', aggregate: 'max', format: 'number', - measure: function (selector) { - var identifiers = getIdentifiers(selector), + measure: function (rawSelector) { + var selector = new CssSelector(rawSelector), + identifiers = selector.getIdentifiers(), specificity = 0; _.each(identifiers, function (identifier) { + identifier = stripNotIdentifier(identifier); + var idIdentifiers = countIdIdentifiers(identifier), classIdentifiers = countClassIdentifiers(identifier), attributeIdentifiers = countAttributeIdentifiers(identifier), @@ -30,17 +34,6 @@ module.exports = { } }; -var getIdentifiers = function (selector) { - var identifiers = [], - segments = selector.split(/\s+[\s\+>]\s?|~^=/g); - - _.each(segments, function (segment) { - identifiers = identifiers.concat(segment.match(/[#\.:]?[\w\-\*]+|\[[\w=\-~'"\|]+\]|:{2}[\w-]+/g)); - }); - - return identifiers; -}; - var getSpecificity = function (idIdentifiers, classIdentifiers, attributeIdentifiers, pseudoClassIdentifiers, typeIdentifiers, pseudoElementIdentifiers) { return Number( String(idIdentifiers) + @@ -53,7 +46,7 @@ var countIdIdentifiers = function (identifier) { var regex = /#/, matches = regex.exec(identifier); - if (matches) { + if (matches && !countAttributeIdentifiers(identifier)) { return matches.length; } @@ -82,8 +75,8 @@ var countAttributeIdentifiers = function (identifier) { return 0; }; -var countPseudoClassIdentifiers = function (identifier) { - var regex = /:[^:]/, +var countPseudoClassIdentifiers = function (identifier) { + var regex = /^:[^:]/, matches = regex.exec(identifier); // :not pseudo-class identifier itself is ignored @@ -119,3 +112,11 @@ var countPseudoElementIdentifiers = function (identifier) { return 0; }; + +var stripNotIdentifier = function (identifier) { + if (identifier.match(/:not/)) { + return identifier.replace(/:not\(|\)/g, ''); + } + + return identifier; +}; diff --git a/test/CssSelector.js b/test/CssSelector.js index fa7ae23..23083c7 100644 --- a/test/CssSelector.js +++ b/test/CssSelector.js @@ -36,7 +36,7 @@ describe('The Selector Parser', function() { it('correctly parses attribute identifiers in a selector', function() { var cssSelector = new CssSelector('form[name=login-form]'); expect(cssSelector.getIdentifiers()).to.have.length(2); - cssSelector = new CssSelector('a[rel][]'); + cssSelector = new CssSelector('a[rel]'); expect(cssSelector.getIdentifiers()).to.have.length(2); cssSelector = new CssSelector('a[rel~="copyright"]'); expect(cssSelector.getIdentifiers()).to.have.length(2); diff --git a/test/TopSelectorSpecificity.js b/test/TopSelectorSpecificity.js index 40935e9..809cec0 100644 --- a/test/TopSelectorSpecificity.js +++ b/test/TopSelectorSpecificity.js @@ -2,9 +2,41 @@ var expect = require('chai').expect, metric = require('../metrics/TopSelectorSpecificity.js'); describe('The top-selector-specificity metric', function () { + it('should return a specificity of "1" for the selector "table"', function () { + expect(metric.measure("table")).to.equal(1); + }); + + it('should return a specificity of "1" for the selector "::first-line"', function () { + expect(metric.measure('::before')).to.equal(1); + }); + + it('should return a specificity of "10" for the selector ".class"', function () { + expect(metric.measure('.class')).to.equal(10); + }); + + it('should return a specificity of "10" for the selector "[href="/"]"', function () { + expect(metric.measure('[href="/"]')).to.equal(10); + }); + + it('should return a specificity of "10" for the selector ":first"', function () { + expect(metric.measure(':first')).to.equal(10); + }); + + it('should return a specificity of "100" for the selector "#main"', function () { + expect(metric.measure('#main')).to.equal(100); + }); + + it('should return a specificity of "0" for the selector "*"', function () { + expect(metric.measure('*')).to.equal(0); + }); + it('should count only the specificity of the child selector of a :not identifier', function () { expect(metric.measure(':not(body)')).to.equal(1); expect(metric.measure(':not(.sidebar)')).to.equal(10); expect(metric.measure(':not(h1#main)')).to.equal(101); }); + + it('should ignore identifier tokens inside attribute selectors', function () { + expect(metric.measure('[href="#main"]')).to.equal(10); + }); }); From a00d7cc7d3a4932af10f4b090a5ff75cffb1c60c Mon Sep 17 00:00:00 2001 From: Bart Veneman Date: Sun, 2 Oct 2016 17:59:03 +0200 Subject: [PATCH 15/15] fixes minor spelling and formatting issues --- test/CliIntegration.js | 5 ++--- test/IdentifiersPerSelector.js | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/test/CliIntegration.js b/test/CliIntegration.js index 051b50c..9b1d4bd 100644 --- a/test/CliIntegration.js +++ b/test/CliIntegration.js @@ -1,6 +1,6 @@ /*! Parker v0.1.0 - MIT license */ -var expect = require('chai').expect +var expect = require('chai').expect, exec = require('child_process').exec; describe('The Parker CLI tool', function () { @@ -41,7 +41,6 @@ describe('The Parker CLI tool', function () { exec('node parker.js test/fixtures/specificity-warning.css --format="warnings"', function (err, stdout, stderr) { expect(stdout).to.contain('Failure: Top Selector Specificity: 900'); expect(stdout).to.contain('Failure: Specificity Per Selector: 900'); - expect(stdout).to.contain('Failure: Top Selector Specificity: 900'); done(); }); }); @@ -57,7 +56,7 @@ describe('The Parker CLI tool', function () { } ); - it('should reduce the threashold at which warnings are reported when invoked with a --warning-figures="strict" switch', function (done) { + it('should reduce the threshold at which warnings are reported when invoked with a --warning-figures="strict" switch', function (done) { exec('node parker.js test/fixtures/one-id-selector.css --format="warnings"', function (defaultErr, defaultStdout, defaultStderr) { exec('node parker.js test/fixtures/one-id-selector.css --format="warnings" --warning-figures="strict"', function (strictErr, strictStdout, strictStderr) { expect(defaultStdout).to.not.contain('Failure: Top Selector Specificity'); diff --git a/test/IdentifiersPerSelector.js b/test/IdentifiersPerSelector.js index f142bab..e54af1c 100644 --- a/test/IdentifiersPerSelector.js +++ b/test/IdentifiersPerSelector.js @@ -35,7 +35,7 @@ describe('The identifiers-per-selector metric', function () { it('should return 5 for the selector "body section.articles>article:first-child"', function() { expect(metric.measure('body section.articles>article:first-child')).to.equal(5); - }) + }); it('should return 7 for the selector "body section.articles>article:first-child p::first-line', function() { expect(metric.measure('body section.articles>article:first-child p::first-line')).to.equal(7);