/
require-render-return.js
97 lines (89 loc) · 2.93 KB
/
require-render-return.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
/**
* @fileoverview Enforce ES5 or ES6 class for returning value in render function.
* @author Mark Orel
*/
'use strict';
const Components = require('../util/Components');
const astUtil = require('../util/ast');
const docsUrl = require('../util/docsUrl');
// ------------------------------------------------------------------------------
// Rule Definition
// ------------------------------------------------------------------------------
module.exports = {
meta: {
docs: {
description: 'Enforce ES5 or ES6 class for returning value in render function',
category: 'Possible Errors',
recommended: true,
url: docsUrl('require-render-return')
},
schema: [{}]
},
create: Components.detect((context, components, utils) => {
/**
* Mark a return statement as present
* @param {ASTNode} node The AST node being checked.
*/
function markReturnStatementPresent(node) {
components.set(node, {
hasReturnStatement: true
});
}
/**
* Check if a given AST node has a render method
* @param {ASTNode} node The AST node being checked.
* @returns {Boolean} True if there is a render method, false if not
*/
function hasRenderMethod(node) {
const properties = astUtil.getComponentProperties(node);
for (let i = 0, j = properties.length; i < j; i++) {
if (astUtil.getPropertyName(properties[i]) !== 'render' || !properties[i].value) {
continue;
}
return astUtil.isFunctionLikeExpression(properties[i].value);
}
return false;
}
return {
ReturnStatement: function(node) {
const ancestors = context.getAncestors(node).reverse();
let depth = 0;
for (let i = 0, j = ancestors.length; i < j; i++) {
if (/Function(Expression|Declaration)$/.test(ancestors[i].type)) {
depth++;
}
if (
!/(MethodDefinition|(Class)?Property)$/.test(ancestors[i].type) ||
astUtil.getPropertyName(ancestors[i]) !== 'render' ||
depth > 1
) {
continue;
}
markReturnStatementPresent(node);
}
},
ArrowFunctionExpression: function(node) {
if (node.expression === false || astUtil.getPropertyName(node.parent) !== 'render') {
return;
}
markReturnStatementPresent(node);
},
'Program:exit': function() {
const list = components.list();
Object.keys(list).forEach(component => {
if (
!hasRenderMethod(list[component].node) ||
list[component].hasReturnStatement ||
(!utils.isES5Component(list[component].node) && !utils.isES6Component(list[component].node))
) {
return;
}
context.report({
node: list[component].node,
message: 'Your render method should have return statement'
});
});
}
};
})
};