58b6764ff1f676398ab94151a017cb1ffe149bcc
[platform/framework/web/crosswalk-tizen.git] /
1 /**
2  * @fileoverview Rule that warns about used warning comments
3  * @author Alexander Schmidt <https://github.com/lxanders>
4  */
5
6 "use strict";
7
8 //------------------------------------------------------------------------------
9 // Rule Definition
10 //------------------------------------------------------------------------------
11
12 module.exports = function (context) {
13
14     var configuration = context.options[0] || {},
15         warningTerms = configuration.terms || ["todo", "fixme", "xxx"],
16         location = configuration.location || "start",
17         warningRegExps;
18
19     /**
20      * Convert a warning term into a RegExp which will match a comment containing that whole word in the specified
21      * location ("start" or "anywhere"). If the term starts or ends with non word characters, then the match will not
22      * require word boundaries on that side.
23      *
24      * @param {String} term A term to convert to a RegExp
25      * @returns {RegExp} The term converted to a RegExp
26      */
27     function convertToRegExp(term) {
28         var escaped = term.replace(/[-\/\\$\^*+?.()|\[\]{}]/g, "\\$&"),
29             // If the term ends in a word character (a-z0-9_), ensure a word boundary at the end, so that substrings do
30             // not get falsely matched. eg "todo" in a string such as "mastodon".
31             // If the term ends in a non-word character, then \b won't match on the boundary to the next non-word
32             // character, which would likely be a space. For example `/\bFIX!\b/.test('FIX! blah') === false`.
33             // In these cases, use no bounding match. Same applies for the prefix, handled below.
34             suffix = /\w$/.test(term) ? "\\b" : "",
35             prefix;
36
37         if (location === "start") {
38             // When matching at the start, ignore leading whitespace, and there's no need to worry about word boundaries
39             prefix = "^\\s*";
40         } else if (/^\w/.test(term)) {
41             prefix = "\\b";
42         } else {
43             prefix = "";
44         }
45
46         return new RegExp(prefix + escaped + suffix, "i");
47     }
48
49     /**
50      * Checks the specified comment for matches of the configured warning terms and returns the matches.
51      * @param {String} comment The comment which is checked.
52      * @returns {Array} All matched warning terms for this comment.
53      */
54     function commentContainsWarningTerm(comment) {
55         var matches = [];
56
57         warningRegExps.forEach(function (regex, index) {
58             if (regex.test(comment)) {
59                 matches.push(warningTerms[index]);
60             }
61         });
62
63         return matches;
64     }
65
66     /**
67      * Checks the specified node for matching warning comments and reports them.
68      * @param {ASTNode} node The AST node being checked.
69      * @returns {void} undefined.
70      */
71     function checkComment(node) {
72         var matches = commentContainsWarningTerm(node.value);
73
74         matches.forEach(function (matchedTerm) {
75             context.report(node, "Unexpected " + matchedTerm + " comment.");
76         });
77     }
78
79     warningRegExps = warningTerms.map(convertToRegExp);
80     return {
81         "BlockComment": checkComment,
82         "LineComment": checkComment
83     };
84 };