Skip to content

Commit 6682673

Browse files
committed
Fix output for checkstyle when a file can't be read (fixes #253)
1 parent 3864557 commit 6682673

4 files changed

Lines changed: 110 additions & 70 deletions

File tree

src/cli/common.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,11 @@ function cli(api){
7575
exitCode = 0;
7676

7777
if (!input) {
78-
api.print("csslint: Could not read file data in " + relativeFilePath + ". Is the file empty?");
78+
if (formatter.readError) {
79+
api.print(formatter.readError(relativeFilePath, "Could not read file data. Is the file empty?"));
80+
} else {
81+
api.print("csslint: Could not read file data in " + relativeFilePath + ". Is the file empty?");
82+
}
7983
exitCode = 1;
8084
} else {
8185
//var relativeFilePath = getRelativePath(api.getWorkingDirectory(), fullFilePath);

src/cli/node.js

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,11 @@ cli({
2929
},
3030

3131
isDirectory: function(name){
32-
return fs.statSync(name).isDirectory();
32+
try {
33+
return fs.statSync(name).isDirectory();
34+
} catch (ex) {
35+
return false;
36+
}
3337
},
3438

3539
getFiles: function(dir){
@@ -72,7 +76,11 @@ cli({
7276
},
7377

7478
readFile: function(filename){
75-
return fs.readFileSync(filename, "utf-8");
79+
try {
80+
return fs.readFileSync(filename, "utf-8");
81+
} catch (ex) {
82+
return "";
83+
}
7684
}
7785
});
7886

src/formatters/checkstyle-xml.js

Lines changed: 93 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,81 +1,109 @@
11
/*global CSSLint*/
2-
CSSLint.addFormatter({
3-
//format information
4-
id: "checkstyle-xml",
5-
name: "Checkstyle XML format",
2+
(function() {
63

74
/**
8-
* Return opening root XML tag.
9-
* @return {String} to prepend before all results
5+
* Replace special characters before write to output.
6+
*
7+
* Rules:
8+
* - single quotes is the escape sequence for double-quotes
9+
* - & is the escape sequence for &
10+
* - &lt; is the escape sequence for <
11+
* - &gt; is the escape sequence for >
12+
*
13+
* @param {String} message to escape
14+
* @return escaped message as {String}
1015
*/
11-
startFormat: function(){
12-
return "<?xml version=\"1.0\" encoding=\"utf-8\"?><checkstyle>";
13-
},
16+
var xmlEscape = function(str) {
17+
if (!str || str.constructor !== String) {
18+
return "";
19+
}
20+
21+
return str.replace(/[\"&><]/g, function(match) {
22+
switch (match) {
23+
case "\"":
24+
return "&quot;";
25+
case "&":
26+
return "&amp;";
27+
case "<":
28+
return "&lt;";
29+
case ">":
30+
return "&gt;";
31+
}
32+
});
33+
};
1434

15-
/**
16-
* Return closing root XML tag.
17-
* @return {String} to append after all results
18-
*/
19-
endFormat: function(){
20-
return "</checkstyle>";
21-
},
35+
CSSLint.addFormatter({
36+
//format information
37+
id: "checkstyle-xml",
38+
name: "Checkstyle XML format",
2239

23-
/**
24-
* Given CSS Lint results for a file, return output for this format.
25-
* @param results {Object} with error and warning messages
26-
* @param filename {String} relative file path
27-
* @param options {Object} (UNUSED for now) specifies special handling of output
28-
* @return {String} output for results
29-
*/
30-
formatResults: function(results, filename, options) {
31-
var messages = results.messages,
32-
output = [];
40+
/**
41+
* Return opening root XML tag.
42+
* @return {String} to prepend before all results
43+
*/
44+
startFormat: function(){
45+
return "<?xml version=\"1.0\" encoding=\"utf-8\"?><checkstyle>";
46+
},
3347

3448
/**
35-
* Generate a source string for a rule.
36-
* Checkstyle source strings usually resemble Java class names e.g
37-
* net.csslint.SomeRuleName
38-
* @param {Object} rule
39-
* @return rule source as {String}
49+
* Return closing root XML tag.
50+
* @return {String} to append after all results
4051
*/
41-
var generateSource = function(rule) {
42-
if (!rule || !('name' in rule)) {
43-
return "";
44-
}
45-
return 'net.csslint.' + rule.name.replace(/\s/g,'');
46-
};
52+
endFormat: function(){
53+
return "</checkstyle>";
54+
},
55+
56+
/**
57+
* Returns message when there is a file read error.
58+
* @param {String} filename The name of the file that caused the error.
59+
* @param {String} message The error message
60+
* @return {String} The error message.
61+
*/
62+
readError: function(filename, message) {
63+
return "<file name=\"" + xmlEscape(filename) + "\"><error line=\"0\" column=\"0\" severty=\"error\" message=\"" + xmlEscape(message) + "\"></error></file>";
64+
},
4765

4866
/**
49-
* Replace special characters before write to output.
50-
*
51-
* Rules:
52-
* - single quotes is the escape sequence for double-quotes
53-
* - &amp; is the escape sequence for &
54-
* - &lt; is the escape sequence for <
55-
* - &gt; is the escape sequence for >
56-
*
57-
* @param {String} message to escape
58-
* @return escaped message as {String}
67+
* Given CSS Lint results for a file, return output for this format.
68+
* @param results {Object} with error and warning messages
69+
* @param filename {String} relative file path
70+
* @param options {Object} (UNUSED for now) specifies special handling of output
71+
* @return {String} output for results
5972
*/
60-
var escapeSpecialCharacters = function(str) {
61-
if (!str || str.constructor !== String) {
62-
return "";
63-
}
64-
return str.replace(/\"/g, "'").replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
65-
};
73+
formatResults: function(results, filename, options) {
74+
var messages = results.messages,
75+
output = [];
6676

67-
if (messages.length > 0) {
68-
output.push("<file name=\""+filename+"\">");
69-
CSSLint.Util.forEach(messages, function (message, i) {
70-
//ignore rollups for now
71-
if (!message.rollup) {
72-
output.push("<error line=\"" + message.line + "\" column=\"" + message.col + "\" severity=\"" + message.type + "\"" +
73-
" message=\"" + escapeSpecialCharacters(message.message) + "\" source=\"" + generateSource(message.rule) +"\"/>");
77+
/**
78+
* Generate a source string for a rule.
79+
* Checkstyle source strings usually resemble Java class names e.g
80+
* net.csslint.SomeRuleName
81+
* @param {Object} rule
82+
* @return rule source as {String}
83+
*/
84+
var generateSource = function(rule) {
85+
if (!rule || !('name' in rule)) {
86+
return "";
7487
}
75-
});
76-
output.push("</file>");
88+
return 'net.csslint.' + rule.name.replace(/\s/g,'');
89+
};
90+
91+
92+
93+
if (messages.length > 0) {
94+
output.push("<file name=\""+filename+"\">");
95+
CSSLint.Util.forEach(messages, function (message, i) {
96+
//ignore rollups for now
97+
if (!message.rollup) {
98+
output.push("<error line=\"" + message.line + "\" column=\"" + message.col + "\" severity=\"" + message.type + "\"" +
99+
" message=\"" + xmlEscape(message.message) + "\" source=\"" + generateSource(message.rule) +"\"/>");
100+
}
101+
});
102+
output.push("</file>");
103+
}
104+
105+
return output.join("");
77106
}
107+
});
78108

79-
return output.join("");
80-
}
81-
});
109+
}());

tests/formatters/checkstyle-xml.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@
3333
{ type: "error", line: 2, col: 1, message: specialCharsSting, evidence: "ALSO BOGUS", rule: [] }
3434
], stats: [] },
3535
file = "<file name=\"FILE\">",
36-
error1 = "<error line=\"1\" column=\"1\" severity=\"warning\" message=\"sneaky, 'sneaky', &lt;sneaky&gt;, sneak &amp; sneaky\" source=\"\"/>",
37-
error2 = "<error line=\"2\" column=\"1\" severity=\"error\" message=\"sneaky, 'sneaky', &lt;sneaky&gt;, sneak &amp; sneaky\" source=\"\"/>",
36+
error1 = "<error line=\"1\" column=\"1\" severity=\"warning\" message=\"sneaky, &quot;sneaky&quot;, &lt;sneaky&gt;, sneak &amp; sneaky\" source=\"\"/>",
37+
error2 = "<error line=\"2\" column=\"1\" severity=\"error\" message=\"sneaky, &quot;sneaky&quot;, &lt;sneaky&gt;, sneak &amp; sneaky\" source=\"\"/>",
3838
expected = "<?xml version=\"1.0\" encoding=\"utf-8\"?><checkstyle>" + file + error1 + error2 + "</file></checkstyle>",
3939
actual = CSSLint.format(result, "FILE", "checkstyle-xml");
4040
Assert.areEqual(expected, actual);

0 commit comments

Comments
 (0)