Skip to content

Commit b4eb1b6

Browse files
committed
An example to detect nested ternary conditionals.
http://code.google.com/p/esprima/issues/detail?id=349
1 parent 2eefe2d commit b4eb1b6

File tree

2 files changed

+129
-0
lines changed

2 files changed

+129
-0
lines changed

doc/index.html

+23
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,29 @@ <h3>Parsing Interface</h3>
108108

109109
<h2 id="examples">Examples</h2>
110110

111+
<h3 id="nestedternary">Detect Nested Ternary Conditionals</h3>
112+
113+
<p>The script <code>detectnestedternary.js</code> in the <code>examples/</code> subdirectory is using Esprima to look for a ternary conditional, i.e. <a href="http://en.wikipedia.org/wiki/%3F:">operator ?:</a>, which is immediately followed (in one of its code paths) by another ternary conditional. The script can be invoked from the command-line with Node.js:</p>
114+
115+
<pre class="prettyprint lang-bsh">
116+
node detectnestedternary.js /some/path
117+
</pre>
118+
119+
<p>An example code fragment which will be flagged by this script as having a nested ternary conditional:</p>
120+
121+
<pre class="prettyprint lang-js">
122+
var str = (age < 1) ? "baby" :
123+
(age < 5) ? "toddler" :
124+
(age < 18) ? "child": "adult";
125+
</pre>
126+
127+
<p>which will yield the following report:</p>
128+
129+
<pre>
130+
Line 1 : Nested ternary for "age &lt 1"
131+
Line 2 : Nested ternary for "age &lt 5"
132+
</pre>
133+
111134
<h3 id="booleantrap">Find Possible Boolean Traps</h3>
112135

113136
<p>The script <code>findbooleantrap.js</code> in the <code>examples/</code> subdirectory is using Esprima to detect some possible cases of Boolean trap, i.e. the use of Boolean literal which may lead to ambiguities and lack of readability. The script can be invoked from command-line with Node.js:</p>

examples/detectnestedternary.js

+106
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
// Usage: node detectnestedternary.js /path/to/some/directory
2+
// For more details, please read http://esprima.org/doc/#nestedternary
3+
4+
/*jslint node:true sloppy:true plusplus:true */
5+
6+
var fs = require('fs'),
7+
esprima = require('../esprima'),
8+
dirname = process.argv[2];
9+
10+
11+
// Executes visitor on the object and its children (recursively).
12+
function traverse(object, visitor) {
13+
var key, child;
14+
15+
visitor.call(null, object);
16+
for (key in object) {
17+
if (object.hasOwnProperty(key)) {
18+
child = object[key];
19+
if (typeof child === 'object' && child !== null) {
20+
traverse(child, visitor);
21+
}
22+
}
23+
}
24+
}
25+
26+
// http://stackoverflow.com/q/5827612/
27+
function walk(dir, done) {
28+
var results = [];
29+
fs.readdir(dir, function (err, list) {
30+
if (err) {
31+
return done(err);
32+
}
33+
var i = 0;
34+
(function next() {
35+
var file = list[i++];
36+
if (!file) {
37+
return done(null, results);
38+
}
39+
file = dir + '/' + file;
40+
fs.stat(file, function (err, stat) {
41+
if (stat && stat.isDirectory()) {
42+
walk(file, function (err, res) {
43+
results = results.concat(res);
44+
next();
45+
});
46+
} else {
47+
results.push(file);
48+
next();
49+
}
50+
});
51+
}());
52+
});
53+
}
54+
55+
walk(dirname, function (err, results) {
56+
if (err) {
57+
console.log('Error', err);
58+
return;
59+
}
60+
61+
results.forEach(function (filename) {
62+
var shortname, first, content, syntax;
63+
64+
shortname = filename;
65+
first = true;
66+
67+
if (shortname.substr(0, dirname.length) === dirname) {
68+
shortname = shortname.substr(dirname.length + 1, shortname.length);
69+
}
70+
71+
function report(node, problem) {
72+
if (first === true) {
73+
console.log(shortname + ': ');
74+
first = false;
75+
}
76+
console.log(' Line', node.loc.start.line, ':', problem);
77+
}
78+
79+
function checkConditional(node) {
80+
var condition;
81+
82+
if (node.consequent.type === 'ConditionalExpression' ||
83+
node.alternate.type === 'ConditionalExpression') {
84+
85+
condition = content.substring(node.test.range[0], node.test.range[1]);
86+
if (condition.length > 20) {
87+
condition = condition.substring(0, 20) + '...';
88+
}
89+
condition = '"' + condition + '"';
90+
report(node, 'Nested ternary for ' + condition);
91+
}
92+
}
93+
94+
try {
95+
content = fs.readFileSync(filename, 'utf-8');
96+
syntax = esprima.parse(content, { tolerant: true, loc: true, range: true });
97+
traverse(syntax, function (node) {
98+
if (node.type === 'ConditionalExpression') {
99+
checkConditional(node);
100+
}
101+
});
102+
} catch (e) {
103+
}
104+
105+
});
106+
});

0 commit comments

Comments
 (0)