mirror of
https://github.com/smogon/pokemon-showdown.git
synced 2026-05-06 05:27:54 -05:00
166 lines
4.0 KiB
JavaScript
166 lines
4.0 KiB
JavaScript
/**
|
|
* Enforces Pokémon Showdown code style for conditionals
|
|
*
|
|
* Type: `Boolean`
|
|
*
|
|
* Value: `true`
|
|
*
|
|
* #### Example
|
|
*
|
|
* ```js
|
|
* "validateConditionals": true
|
|
* ```
|
|
*
|
|
* ##### Valid
|
|
*
|
|
* ```js
|
|
* if (console.log) {
|
|
* console.log("Test");
|
|
* }
|
|
*
|
|
* if (console.log) {
|
|
* console.log("Test");
|
|
* } else {
|
|
* throw new Error("Error");
|
|
* }
|
|
*
|
|
* if (console.log) {
|
|
* console.log("Test");
|
|
* } else {
|
|
* 0;
|
|
* }
|
|
*
|
|
* if (console.log) {
|
|
* console.log("Test");
|
|
* } else if (Number.isFinite) {
|
|
* Number.isFinite(42);
|
|
* }
|
|
*
|
|
* if (Math.random) Math.random();
|
|
*
|
|
* if (a == 1) // Do something with this magic number
|
|
* ```
|
|
*
|
|
* ##### Invalid
|
|
*
|
|
* ```js
|
|
* if (console.log) {
|
|
* console.log("Test");
|
|
* } else if (Number.isFinite) Number.isFinite();
|
|
*
|
|
* if (Math.random) {
|
|
* Math.random();
|
|
* } else {Number.isFinite()};
|
|
*
|
|
* if (Math.random) {
|
|
* Math.random();
|
|
* } else if (Number.isFinite) {Number.isFinite()};
|
|
*
|
|
* if (Math.random) Math.random();
|
|
* else {
|
|
* Number.isFinite();
|
|
* }
|
|
*
|
|
* if (Math.random) Math.random(); else Number.isFinite();
|
|
*
|
|
* if (Math.random) Math.random();
|
|
* else Number.isFinite();
|
|
*
|
|
* if (Math.random) Math.random();
|
|
* else if (Number.isFinite) Number.isFinite();
|
|
* else Number.isInteger();
|
|
*
|
|
* if (Math.random)
|
|
* Math.random();
|
|
*
|
|
* ```
|
|
*/
|
|
|
|
var assert = require('assert');
|
|
|
|
module.exports = function () {};
|
|
|
|
module.exports.prototype = {
|
|
|
|
configure: function (options) {
|
|
assert(
|
|
options === true,
|
|
this.getOptionName() + ' option requires a true value or should be removed'
|
|
);
|
|
},
|
|
|
|
getOptionName: function () {
|
|
return 'validateConditionals';
|
|
},
|
|
|
|
check: function (file, errors) {
|
|
file.iterateNodesByType('IfStatement', function (node) {
|
|
var consequent = node.consequent;
|
|
var statementType = consequent.type;
|
|
|
|
// Either all `BlockStatement` or none.
|
|
var subNode = node;
|
|
while (subNode.alternate) {
|
|
subNode = subNode.alternate;
|
|
if (subNode.type === 'IfStatement') {
|
|
if (subNode.consequent.type !== statementType) {
|
|
errors.add("Mixed conditional blocks and expressions are disallowed", subNode.loc.start);
|
|
break;
|
|
} else if (subNode.consequent.type !== 'BlockStatement') {
|
|
errors.add("Nested conditionals require curly braces", subNode.loc.start);
|
|
break;
|
|
}
|
|
} else {
|
|
if (subNode.type !== statementType && (subNode.type === 'BlockStatement' || statementType === 'BlockStatement')) {
|
|
errors.add("Mixed conditional blocks and expressions are disallowed", subNode.loc.start);
|
|
} else if (subNode.type !== 'BlockStatement') {
|
|
errors.add("Nested conditionals require curly braces", subNode.loc.start);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Curly braces iff multiline
|
|
var nodesCheck = [consequent];
|
|
if (node.alternate) nodesCheck.push(node.alternate);
|
|
for (var i = 0; i < nodesCheck.length; i++) {
|
|
var subNode = nodesCheck[i];
|
|
if (subNode.type === 'BlockStatement') {
|
|
var openingBrace = file.getFirstNodeToken(subNode);
|
|
var closingBrace = file.getLastNodeToken(subNode);
|
|
if (!subNode.body.length) {
|
|
// Empty block
|
|
errors.assert.differentLine({
|
|
token: openingBrace,
|
|
nextToken: closingBrace
|
|
});
|
|
continue;
|
|
}
|
|
var nextToken = file.getFirstNodeToken(subNode.body[0]);
|
|
var prevToken = file.getPrevToken(closingBrace);
|
|
|
|
errors.assert.differentLine({
|
|
token: openingBrace,
|
|
nextToken: nextToken,
|
|
message: 'Newline after opening curly brace required for block conditional (a)'
|
|
});
|
|
errors.assert.differentLine({
|
|
token: prevToken,
|
|
nextToken: closingBrace,
|
|
message: 'Newline before closing curly brace required for block conditional (b)'
|
|
});
|
|
} else if (subNode.type !== 'IfStatement') {
|
|
if (subNode === consequent) {
|
|
var token = file.getFirstNodeToken(subNode);
|
|
errors.assert.sameLine({
|
|
token: node.test,
|
|
nextToken: token,
|
|
message: 'Newline disallowed in non-block conditional (b)'
|
|
});
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
};
|