From 517ffe4e17556e1b9d1c3eda0b394a07417ead54 Mon Sep 17 00:00:00 2001 From: dmi3y Date: Sun, 13 Apr 2014 10:02:59 -0700 Subject: [PATCH 1/4] cli config path #449 --- src/cli/common.js | 68 +++++++++++++++++++++++++++++++++++------------ 1 file changed, 51 insertions(+), 17 deletions(-) diff --git a/src/cli/common.js b/src/cli/common.js index fd6867bb..15526070 100644 --- a/src/cli/common.js +++ b/src/cli/common.js @@ -16,6 +16,7 @@ function cli(api){ "warnings" : { "format" : "", "description" : "Indicate which rules to include as warnings."}, "ignore" : { "format" : "", "description" : "Indicate which rules to ignore completely."}, "exclude-list": { "format" : "", "description" : "Indicate which files/directories to exclude from being linted."}, + "config" : { "format" : "", "description" : "Reads csslint options from specified file."}, "version" : { "format" : "", "description" : "Outputs the current version number."} }; @@ -250,8 +251,9 @@ function cli(api){ } - function processArguments(args, options) { + function processArguments(args, extend) { var arg = args.shift(), + options = extend || {}, argName, parts, files = []; @@ -293,9 +295,16 @@ function cli(api){ } } - function readConfigFile(options) { - var data = api.readFile(api.getFullPath(".csslintrc")), - json; + function readConfigFile(config) { + var csslintrc = config || ".csslintrc", + data = api.readFile(api.getFullPath(csslintrc)); + return data; + } + + function readConfigData(config) { + var data = readConfigFile(config), + json, + options = {}; if (data) { if (data.charAt(0) === "{") { try { @@ -308,13 +317,33 @@ function cli(api){ } } catch(e) {} } - options = processArguments(data.split(/[\s\n\r]+/m), options); + options = processArguments(data.split(/[\s\n\r]+/m)); } return options; } + function mergeOptions(/*arguments*/) { + var allOptions = Array.apply(null, arguments).sort(), + allOptionsCount = allOptions.length, + options = allOptions[0], + overrideOptions, + overrideOptionix, + overrideOption; + + for (var i = 1; i < allOptionsCount; i += 1) { + overrideOptions = allOptions[i]; + + for (overrideOptionix in overrideOptions) { + if (overrideOptions.hasOwnProperty(overrideOptionix)) { + overrideOption = overrideOptions[overrideOptionix]; + options[overrideOptionix] = overrideOption; + } + } + } + return options; + } //----------------------------------------------------------------------------- // Process command line @@ -322,31 +351,36 @@ function cli(api){ var args = api.args, argCount = args.length, - options = {}; + options, + rcOptions, + cliOptions; - // first look for config file .csslintrc - options = readConfigFile(options); - - // Command line arguments override config file - options = processArguments(args, options); + // Preprocess command line arguments + cliOptions = processArguments(args); - if (options.help || argCount === 0){ + if (cliOptions.help || argCount === 0){ outputHelp(); api.quit(0); } - // Validate options - validateOptions(options); - - if (options.version){ + if (cliOptions.version){ api.print("v" + CSSLint.version); api.quit(0); } - if (options["list-rules"]){ + if (cliOptions["list-rules"]){ printRules(); api.quit(0); } + // Look for config file + rcOptions = readConfigData(cliOptions.config); + + // Command line arguments override config file + options = mergeOptions(rcOptions, cliOptions); + + // Validate options + validateOptions(options); + api.quit(processFiles(options.files,options)); } From 4b19770718fb0af024dd38233176f8a60b3d8d16 Mon Sep 17 00:00:00 2001 From: dmi3y Date: Tue, 15 Apr 2014 00:58:06 -0700 Subject: [PATCH 2/4] wraping up with cli tests+ CSSLint mix helper from utils to mix up cli and rc options --- src/cli/common.js | 28 +++----------- tests/cli/assets/apiStub.js | 68 ++++++++++++++++++++++++++++++++++ tests/cli/assets/data.js | 43 +++++++++++++++++++++ tests/cli/cli-common.js | 74 +++++++++++++++++++++++++++++++++++++ 4 files changed, 190 insertions(+), 23 deletions(-) create mode 100644 tests/cli/assets/apiStub.js create mode 100644 tests/cli/assets/data.js create mode 100644 tests/cli/cli-common.js diff --git a/src/cli/common.js b/src/cli/common.js index 15526070..ee57f81f 100644 --- a/src/cli/common.js +++ b/src/cli/common.js @@ -323,28 +323,6 @@ function cli(api){ return options; } - function mergeOptions(/*arguments*/) { - var allOptions = Array.apply(null, arguments).sort(), - allOptionsCount = allOptions.length, - options = allOptions[0], - overrideOptions, - overrideOptionix, - overrideOption; - - for (var i = 1; i < allOptionsCount; i += 1) { - overrideOptions = allOptions[i]; - - for (overrideOptionix in overrideOptions) { - if (overrideOptions.hasOwnProperty(overrideOptionix)) { - overrideOption = overrideOptions[overrideOptionix]; - options[overrideOptionix] = overrideOption; - } - } - } - - return options; - } - //----------------------------------------------------------------------------- // Process command line //----------------------------------------------------------------------------- @@ -377,7 +355,11 @@ function cli(api){ rcOptions = readConfigData(cliOptions.config); // Command line arguments override config file - options = mergeOptions(rcOptions, cliOptions); + options = CSSLint.Util.mix(rcOptions, cliOptions); + + // hot fix for CSSLint.Util.mix current behavior + // https://github.com/CSSLint/csslint/issues/501 + options = rcOptions; // Validate options validateOptions(options); diff --git a/tests/cli/assets/apiStub.js b/tests/cli/assets/apiStub.js new file mode 100644 index 00000000..fbf2390d --- /dev/null +++ b/tests/cli/assets/apiStub.js @@ -0,0 +1,68 @@ +/*jshint node:true*/ +"use strict"; +var + stub = { + logbook: function (log) { + this.logs.push(log); + }, + readLogs: function () { + return this.logs.slice(); + }, + + getFullPath: function (path) { + return path; + }, + getFiles: function (dir) { + var + filesobj = this.fakedFs[dir], + fileix, + out = []; + for (fileix in filesobj) { + if ( filesobj.hasOwnProperty(fileix) && /\.css$/.test(fileix) ) { + out.push(dir + "/" + fileix); + } + } + return out; + }, + readFile: function (path) { + var + spath = path.split("/"), + spathLen = spath.length, + i, + out = this.fakedFs; + + for (i = 0; i < spathLen; i += 1) { + out = out[spath[i]]; + } + + return out; + }, + isDirectory: function (checkit) { + var + result = this.fakedFs[checkit]; + return typeof result === "object"; + }, + print: function (msg) { + this.logbook(msg); + }, + quit: function (signal) { + this.logbook(signal); + } + }; + +module.exports = function (setup) { + var + api, + setix; + + api = Object.create(stub); + + for (setix in setup) { + if (setup.hasOwnProperty(setix)) { + api[setix] = setup[setix]; + } + } + + api.logs = []; + return api; +}; diff --git a/tests/cli/assets/data.js b/tests/cli/assets/data.js new file mode 100644 index 00000000..e04b5ca4 --- /dev/null +++ b/tests/cli/assets/data.js @@ -0,0 +1,43 @@ +/*jshint node:true*/ +module.exports = { + "suites": { + "config csslintrc override": { + "args": [ + "--config=.rc1", + "dir" + ], + "expecting": [ + "csslint: No errors in dir/a.css.", + "csslint: No errors in dir/b.css.", + 0 + ] + }, + "straight linting": { + "args": [ + "dir" + ], + "expecting": [ + "csslint: There is 1 problem in dir/a.css.", + "csslint: There is 1 problem in dir/b.css.", + 0 + ] + }, + "version": { + "args": [ + "--version" + ], + "expecting": [ + "v@VERSION@", + 0 + ] + } + }, + + "fakedFs": { + ".rc1": "--ignore=important,ids", + "dir": { + "a.css": ".a {color: red!important;}", + "b.css": "#a {color: red;}" + }, + } +}; diff --git a/tests/cli/cli-common.js b/tests/cli/cli-common.js new file mode 100644 index 00000000..0e1b6baf --- /dev/null +++ b/tests/cli/cli-common.js @@ -0,0 +1,74 @@ +/*jshint loopfunc:true, node:true */ +// mainly for testing --config cli option +"use strict"; +function include(path, sandbox) { + var + vm = require("vm"), + fs = require("fs"), + file; + + file = fs.readFileSync(path); + vm.runInNewContext(file, sandbox); +} + + + +(function(){ + + var Assert = YUITest.Assert, + suite = new YUITest.TestSuite("General Tests for CLI"), + apiStub = require("./tests/cli/assets/apiStub.js"), + data = require("./tests/cli/assets/data.js"), + suites = data.suites, + suiteix, + sandbox = { + CSSLint: CSSLint + }; + + include(__dirname + "/src/cli/common.js", sandbox); /* expose sandbox.cli */ + + for (suiteix in suites) { + if (suites.hasOwnProperty(suiteix)) { + (function (suiteix) { + + suite.add(new YUITest.TestCase({ + + name: "Test " + suiteix, + + "Outcome logs should match expected": function (){ + var + it = suites[suiteix], + expecting = it.expecting, + expectingLen = expecting.length, + outcome, + api, + exp, + out, + i = 0; + + data.args = it.args.slice(); + api = apiStub(data); + sandbox.cli(api); + outcome = api.readLogs(); + + for (i; i < expectingLen; i += 1) { + exp = expecting[i]; + out = outcome[i]; + + if ( typeof out === "string") { + out = /^.*/.exec(out.trim())[0]; + } + if ( exp !== out ) { + Assert.fail("Expecting: " + exp + " Got: " + out); + } + } + Assert.pass(); + + } + })); + })(suiteix); + } + } + + YUITest.TestRunner.add(suite); +})(); From 4994199f4503022d397c96e181b3bc529bd98f0c Mon Sep 17 00:00:00 2001 From: dmi3y Date: Wed, 16 Apr 2014 01:44:45 -0700 Subject: [PATCH 3/4] more tests --- tests/cli/assets/data.js | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tests/cli/assets/data.js b/tests/cli/assets/data.js index e04b5ca4..cf74db71 100644 --- a/tests/cli/assets/data.js +++ b/tests/cli/assets/data.js @@ -22,6 +22,30 @@ module.exports = { 0 ] }, + "mix of cli options": { + "args": [ + "--config=.rc1", + "--ignore=important", + "dir" + ], + "expecting": [ + "csslint: No errors in dir/a.css.", + "csslint: There is 1 problem in dir/b.css.", + 0 + ] + }, + "more mixes of cli options": { + "args": [ + "--config=.rc1", + "--errors=important", + "dir" + ], + "expecting": [ + "csslint: There is 1 problem in dir/a.css.", + "csslint: No errors in dir/b.css.", + 1 + ] + }, "version": { "args": [ "--version" From e6c106789bcb6429efa4ea7dfc25093228dc229c Mon Sep 17 00:00:00 2001 From: dmi3y Date: Tue, 15 Apr 2014 00:58:06 -0700 Subject: [PATCH 4/4] wraping up with cli tests+ CSSLint mix helper from utils to mix up cli and rc options --- src/cli/common.js | 28 +++----------- tests/cli/assets/apiStub.js | 68 ++++++++++++++++++++++++++++++++++ tests/cli/assets/data.js | 67 ++++++++++++++++++++++++++++++++++ tests/cli/cli-common.js | 73 +++++++++++++++++++++++++++++++++++++ 4 files changed, 213 insertions(+), 23 deletions(-) create mode 100644 tests/cli/assets/apiStub.js create mode 100644 tests/cli/assets/data.js create mode 100644 tests/cli/cli-common.js diff --git a/src/cli/common.js b/src/cli/common.js index 15526070..ee57f81f 100644 --- a/src/cli/common.js +++ b/src/cli/common.js @@ -323,28 +323,6 @@ function cli(api){ return options; } - function mergeOptions(/*arguments*/) { - var allOptions = Array.apply(null, arguments).sort(), - allOptionsCount = allOptions.length, - options = allOptions[0], - overrideOptions, - overrideOptionix, - overrideOption; - - for (var i = 1; i < allOptionsCount; i += 1) { - overrideOptions = allOptions[i]; - - for (overrideOptionix in overrideOptions) { - if (overrideOptions.hasOwnProperty(overrideOptionix)) { - overrideOption = overrideOptions[overrideOptionix]; - options[overrideOptionix] = overrideOption; - } - } - } - - return options; - } - //----------------------------------------------------------------------------- // Process command line //----------------------------------------------------------------------------- @@ -377,7 +355,11 @@ function cli(api){ rcOptions = readConfigData(cliOptions.config); // Command line arguments override config file - options = mergeOptions(rcOptions, cliOptions); + options = CSSLint.Util.mix(rcOptions, cliOptions); + + // hot fix for CSSLint.Util.mix current behavior + // https://github.com/CSSLint/csslint/issues/501 + options = rcOptions; // Validate options validateOptions(options); diff --git a/tests/cli/assets/apiStub.js b/tests/cli/assets/apiStub.js new file mode 100644 index 00000000..fbf2390d --- /dev/null +++ b/tests/cli/assets/apiStub.js @@ -0,0 +1,68 @@ +/*jshint node:true*/ +"use strict"; +var + stub = { + logbook: function (log) { + this.logs.push(log); + }, + readLogs: function () { + return this.logs.slice(); + }, + + getFullPath: function (path) { + return path; + }, + getFiles: function (dir) { + var + filesobj = this.fakedFs[dir], + fileix, + out = []; + for (fileix in filesobj) { + if ( filesobj.hasOwnProperty(fileix) && /\.css$/.test(fileix) ) { + out.push(dir + "/" + fileix); + } + } + return out; + }, + readFile: function (path) { + var + spath = path.split("/"), + spathLen = spath.length, + i, + out = this.fakedFs; + + for (i = 0; i < spathLen; i += 1) { + out = out[spath[i]]; + } + + return out; + }, + isDirectory: function (checkit) { + var + result = this.fakedFs[checkit]; + return typeof result === "object"; + }, + print: function (msg) { + this.logbook(msg); + }, + quit: function (signal) { + this.logbook(signal); + } + }; + +module.exports = function (setup) { + var + api, + setix; + + api = Object.create(stub); + + for (setix in setup) { + if (setup.hasOwnProperty(setix)) { + api[setix] = setup[setix]; + } + } + + api.logs = []; + return api; +}; diff --git a/tests/cli/assets/data.js b/tests/cli/assets/data.js new file mode 100644 index 00000000..cf74db71 --- /dev/null +++ b/tests/cli/assets/data.js @@ -0,0 +1,67 @@ +/*jshint node:true*/ +module.exports = { + "suites": { + "config csslintrc override": { + "args": [ + "--config=.rc1", + "dir" + ], + "expecting": [ + "csslint: No errors in dir/a.css.", + "csslint: No errors in dir/b.css.", + 0 + ] + }, + "straight linting": { + "args": [ + "dir" + ], + "expecting": [ + "csslint: There is 1 problem in dir/a.css.", + "csslint: There is 1 problem in dir/b.css.", + 0 + ] + }, + "mix of cli options": { + "args": [ + "--config=.rc1", + "--ignore=important", + "dir" + ], + "expecting": [ + "csslint: No errors in dir/a.css.", + "csslint: There is 1 problem in dir/b.css.", + 0 + ] + }, + "more mixes of cli options": { + "args": [ + "--config=.rc1", + "--errors=important", + "dir" + ], + "expecting": [ + "csslint: There is 1 problem in dir/a.css.", + "csslint: No errors in dir/b.css.", + 1 + ] + }, + "version": { + "args": [ + "--version" + ], + "expecting": [ + "v@VERSION@", + 0 + ] + } + }, + + "fakedFs": { + ".rc1": "--ignore=important,ids", + "dir": { + "a.css": ".a {color: red!important;}", + "b.css": "#a {color: red;}" + }, + } +}; diff --git a/tests/cli/cli-common.js b/tests/cli/cli-common.js new file mode 100644 index 00000000..012196bd --- /dev/null +++ b/tests/cli/cli-common.js @@ -0,0 +1,73 @@ +/*jshint loopfunc:true, node:true */ +"use strict"; +function include(path, sandbox) { + var + vm = require("vm"), + fs = require("fs"), + file; + + file = fs.readFileSync(path); + vm.runInNewContext(file, sandbox); +} + + + +(function(){ + + var Assert = YUITest.Assert, + suite = new YUITest.TestSuite("General Tests for CLI"), + apiStub = require("./tests/cli/assets/apiStub.js"), + data = require("./tests/cli/assets/data.js"), + suites = data.suites, + suiteix, + sandbox = { + CSSLint: CSSLint + }; + + include(__dirname + "/src/cli/common.js", sandbox); /* expose sandbox.cli */ + + for (suiteix in suites) { + if (suites.hasOwnProperty(suiteix)) { + (function (suiteix) { + + suite.add(new YUITest.TestCase({ + + name: "Test " + suiteix, + + "Outcome logs should match expected": function (){ + var + it = suites[suiteix], + expecting = it.expecting, + expectingLen = expecting.length, + outcome, + api, + exp, + out, + i = 0; + + data.args = it.args.slice(); + api = apiStub(data); + sandbox.cli(api); + outcome = api.readLogs(); + + for (i; i < expectingLen; i += 1) { + exp = expecting[i]; + out = outcome[i]; + + if ( typeof out === "string") { + out = /^.*/.exec(out.trim())[0]; + } + if ( exp !== out ) { + Assert.fail("Expecting: " + exp + " Got: " + out); + } + } + Assert.pass(); + + } + })); + })(suiteix); + } + } + + YUITest.TestRunner.add(suite); +})();