Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Clone in Desktop Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

executable file 276 lines (229 sloc) 6.39 KB
/**
* Requires the first alphabetical character of a comment to be uppercase, unless it is part of a multi-line textblock.
*
* This rule automatically ignores jscs, jshint, eslint and istanbul specific comments.
*
* Types: `Boolean` or `Object`
*
* Values:
* - `true`
* - `Object`:
* - `allExcept`: array of quoted exceptions
*
* #### Example
*
* ```js
* "requireCapitalizedComments": true
* ```
*
* ##### Valid:
*
* ```js
* // Valid
* //Valid
*
* /*
* Valid
* *\/
*
* /**
* * Valid
* *\/
*
* // A textblock is a set of lines
* // that starts with a capitalized letter
* // and has one or more non-capitalized lines
* // afterwards
*
* // A textblock may also have multiple lines.
* // Those lines can be uppercase as well to support
* // sentense breaks in textblocks
*
* // 123 or any non-alphabetical starting character
* // @are also valid anywhere
*
* // jscs: enable
* ```
*
* ##### Invalid:
*
* ```js
* // invalid
* //invalid
* /** invalid *\/
* /**
* * invalid
* *\/
* ```
*
* ```js
* "requireCapitalizedComments": { "allExcept": ["pragma"] }
* ```
*
* ##### Valid:
*
* ```js
* function sayHello() {
* /* pragma something *\/
*
* // I can now say hello in lots of statements, if I like.
* return "Hello";
* }
* ```
*
* ##### Valid:
*
* ```js
* function sayHello() {
* /* istanbul ignore next *\/
*
* // I'd like to ignore this statement in coverage reports.
* return "Hello";
* }
* ```
*
* ##### Invalid:
*
* ```js
* function sayHello() {
* /* otherPragma something *\/
*
* // i can now say hello in lots of statements, if I like.
* return "Hello";
* }
* ```
*
*/
var assert = require('assert');
var isPragma = require('../utils').isPragma;
var letterPattern = require('../../patterns/L');
var upperCasePattern = require('../../patterns/Lu');
module.exports = function() {};
module.exports.prototype = {
configure: function(options) {
var exceptions;
this._ignoreIfInTheMiddle = false;
this._isPragma = null;
var optionName = this.getOptionName();
var isObject = typeof options === 'object';
var error = optionName + ' option requires a true value ' +
'or an object with String[] `allExcept` property or true with `ignoreIfInTheMiddle`';
assert(
options === true ||
isObject,
error
);
if (isObject && options.allExcept) {
exceptions = options.allExcept;
// verify items in `allExcept` property in object are string values
assert(
Array.isArray(exceptions) &&
exceptions.every(function(el) { return typeof el === 'string'; }),
'Property `allExcept` in ' + optionName + ' should be an array of strings'
);
this._isPragma = isPragma(exceptions);
}
if (!this._isPragma) {
this._isPragma = isPragma();
}
if (isObject && options.ignoreIfInTheMiddle) {
this._ignoreIfInTheMiddle = true;
}
if (isObject && !options.allExcept && !options.ignoreIfInTheMiddle) {
assert(false, error);
}
},
getOptionName: function() {
return 'requireCapitalizedComments';
},
_isUrl: function(comment) {
var protocolParts = comment.value.split('://');
if (protocolParts.length === 1) {
return false;
}
return comment.value.indexOf(protocolParts[0]) === 0;
},
_isException: function(comment) {
return this._isPragma(comment.value);
},
_isValid: function(comment) {
var first = this._getFirstChar(comment);
return first && upperCasePattern.test(first);
},
_isLetter: function(comment) {
var first = this._getFirstChar(comment);
return first && letterPattern.test(first);
},
_getFirstChar: function(comment) {
return comment.value.replace(/[\n\s\*]/g, '')[0];
},
_isTextBlock: function(comment, comments, index) {
var prevComment = comments[index - 1];
if (prevComment) {
return prevComment.type === 'Line' &&
prevComment.loc.start.line + 1 === comment.loc.start.line &&
prevComment.value.trim().length > 0;
}
return false;
},
_shouldIgnoreIfInTheMiddle: function(file, comment) {
if (!this._ignoreIfInTheMiddle) {
return false;
}
var firstToken = file.getFirstNodeToken(comment);
var otherToken = file.getPrevToken(firstToken, { includeComments: true });
return otherToken ? otherToken.loc.start.line === firstToken.loc.start.line : false;
},
check: function(file, errors) {
var _this = this;
function add(comment) {
errors.cast({
message: 'Comments must start with an uppercase letter, unless it is part of a textblock',
line: comment.loc.start.line,
column: comment.loc.start.column,
additional: comment
});
}
file.iterateTokensByType('Line', function(comment, index, comments) {
if (_this._isException(comment)) {
return;
}
if (_this._isUrl(comment)) {
return;
}
if (!_this._isLetter(comment)) {
return;
}
if (_this._isTextBlock(comment, comments, index)) {
return;
}
if (_this._isValid(comment)) {
return;
}
add(comment);
});
file.iterateTokensByType('Block', function(comment, index, comments) {
if (_this._isException(comment)) {
return;
}
if (_this._isUrl(comment)) {
return;
}
if (!_this._isLetter(comment)) {
return;
}
if (_this._shouldIgnoreIfInTheMiddle(file, comment)) {
return;
}
if (_this._isValid(comment, index, comments)) {
return;
}
add(comment);
});
},
_fix: function(file, error) {
var comment = error.additional;
var first = this._getFirstChar(comment);
comment.value = comment.value.replace(first, first.toUpperCase());
}
};
Jump to Line
Something went wrong with that request. Please try again.