UI for Zipcoin Blue

findbooleantrap.js 5.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. // Usage: node findbooleantrap.js /path/to/some/directory
  2. // For more details, please read http://esprima.org/doc/#booleantrap.
  3. /*jslint node:true sloppy:true plusplus:true */
  4. var fs = require('fs'),
  5. esprima = require('../esprima'),
  6. dirname = process.argv[2],
  7. doubleNegativeList = [];
  8. // Black-list of terms with double-negative meaning.
  9. doubleNegativeList = [
  10. 'hidden',
  11. 'caseinsensitive',
  12. 'disabled'
  13. ];
  14. // Executes visitor on the object and its children (recursively).
  15. function traverse(object, visitor) {
  16. var key, child;
  17. if (visitor.call(null, object) === false) {
  18. return;
  19. }
  20. for (key in object) {
  21. if (object.hasOwnProperty(key)) {
  22. child = object[key];
  23. if (typeof child === 'object' && child !== null) {
  24. traverse(child, visitor);
  25. }
  26. }
  27. }
  28. }
  29. // http://stackoverflow.com/q/5827612/
  30. function walk(dir, done) {
  31. var results = [];
  32. fs.readdir(dir, function (err, list) {
  33. if (err) {
  34. return done(err);
  35. }
  36. var i = 0;
  37. (function next() {
  38. var file = list[i++];
  39. if (!file) {
  40. return done(null, results);
  41. }
  42. file = dir + '/' + file;
  43. fs.stat(file, function (err, stat) {
  44. if (stat && stat.isDirectory()) {
  45. walk(file, function (err, res) {
  46. results = results.concat(res);
  47. next();
  48. });
  49. } else {
  50. results.push(file);
  51. next();
  52. }
  53. });
  54. }());
  55. });
  56. }
  57. walk(dirname, function (err, results) {
  58. if (err) {
  59. console.log('Error', err);
  60. return;
  61. }
  62. results.forEach(function (filename) {
  63. var shortname, first, content, syntax;
  64. shortname = filename;
  65. first = true;
  66. if (shortname.substr(0, dirname.length) === dirname) {
  67. shortname = shortname.substr(dirname.length + 1, shortname.length);
  68. }
  69. function getFunctionName(node) {
  70. if (node.callee.type === 'Identifier') {
  71. return node.callee.name;
  72. }
  73. if (node.callee.type === 'MemberExpression') {
  74. return node.callee.property.name;
  75. }
  76. }
  77. function report(node, problem) {
  78. if (first === true) {
  79. console.log(shortname + ': ');
  80. first = false;
  81. }
  82. console.log(' Line', node.loc.start.line, 'in function',
  83. getFunctionName(node) + ':', problem);
  84. }
  85. function checkSingleArgument(node) {
  86. var args = node['arguments'],
  87. functionName = getFunctionName(node);
  88. if ((args.length !== 1) || (typeof args[0].value !== 'boolean')) {
  89. return;
  90. }
  91. // Check if the method is a setter, i.e. starts with 'set',
  92. // e.g. 'setEnabled(false)'.
  93. if (functionName.substr(0, 3) !== 'set') {
  94. report(node, 'Boolean literal with a non-setter function');
  95. }
  96. // Does it contain a term with double-negative meaning?
  97. doubleNegativeList.forEach(function (term) {
  98. if (functionName.toLowerCase().indexOf(term.toLowerCase()) >= 0) {
  99. report(node, 'Boolean literal with confusing double-negative');
  100. }
  101. });
  102. }
  103. function checkMultipleArguments(node) {
  104. var args = node['arguments'],
  105. literalCount = 0;
  106. args.forEach(function (arg) {
  107. if (typeof arg.value === 'boolean') {
  108. literalCount++;
  109. }
  110. });
  111. // At least two arguments must be Boolean literals.
  112. if (literalCount >= 2) {
  113. // Check for two different Boolean literals in one call.
  114. if (literalCount === 2 && args.length === 2) {
  115. if (args[0].value !== args[1].value) {
  116. report(node, 'Confusing true vs false');
  117. return;
  118. }
  119. }
  120. report(node, 'Multiple Boolean literals');
  121. }
  122. }
  123. function checkLastArgument(node) {
  124. var args = node['arguments'];
  125. if (args.length < 2) {
  126. return;
  127. }
  128. if (typeof args[args.length - 1].value === 'boolean') {
  129. report(node, 'Ambiguous Boolean literal as the last argument');
  130. }
  131. }
  132. try {
  133. content = fs.readFileSync(filename, 'utf-8');
  134. syntax = esprima.parse(content, { tolerant: true, loc: true });
  135. traverse(syntax, function (node) {
  136. if (node.type === 'CallExpression') {
  137. checkSingleArgument(node);
  138. checkLastArgument(node);
  139. checkMultipleArguments(node);
  140. }
  141. });
  142. } catch (e) {
  143. }
  144. });
  145. });