This repository has been archived by the owner on Dec 12, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.js
192 lines (162 loc) · 6.49 KB
/
index.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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
/**
* @fileoverview A rule to set the maximum number of comments in a function body. Based on core rule max-lines-per-function.
* @author Pete Ward <[email protected]>
* @author M. Ian Graham <[email protected]>
*/
'use strict';
//------------------------------------------------------------------------------
// Requirements
//------------------------------------------------------------------------------
const astUtils = require('eslint/lib/util/ast-utils');
//------------------------------------------------------------------------------
// Constants
//------------------------------------------------------------------------------
const OPTIONS_SCHEMA = {
type: 'object',
properties: {
max: {
type: 'integer',
minimum: 0
}
},
additionalProperties: false
};
const OPTIONS_OR_INTEGER_SCHEMA = {
oneOf: [
OPTIONS_SCHEMA,
{
type: 'integer',
minimum: 1
}
]
};
/**
* Given a list of comment nodes, return a map with numeric keys (source code line numbers) and comment token values.
* @param {Array} comments An array of comment nodes.
* @returns {Map.<string,Node>} A map with numeric keys (source code line numbers) and comment token values.
*/
function getCommentLineNumbers(comments) {
const map = new Map();
if (!comments) {
return map;
}
comments.forEach(comment => {
for (let i = comment.loc.start.line; i <= comment.loc.end.line; i++) {
map.set(i, comment);
}
});
return map;
}
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
module.exports.rules = {
'max-comments-per-function': {
meta: {
type: 'suggestion',
docs: {
description: 'enforce a maximum number of comments in a function',
category: 'Stylistic Issues',
recommended: false,
url: 'https://github.com/miangraham/eslint-plugin-max-comments-per-function'
},
schema: [OPTIONS_OR_INTEGER_SCHEMA]
},
create(context) {
const sourceCode = context.getSourceCode();
const lines = sourceCode.lines;
const option = context.options[0];
let maxComments = 50;
if (typeof option === 'object') {
if (typeof option.max === 'number') {
maxComments = option.max;
}
} else if (typeof option === 'number') {
maxComments = option;
}
const commentLineNumbers = getCommentLineNumbers(sourceCode.getAllComments());
//--------------------------------------------------------------------------
// Helpers
//--------------------------------------------------------------------------
/**
* Tells if a comment encompasses the entire line.
* @param {string} line The source line with a trailing comment
* @param {number} lineNumber The one-indexed line number this is on
* @param {ASTNode} comment The comment to remove
* @returns {boolean} If the comment covers the entire line
*/
function isFullLineComment(line, lineNumber, comment) {
const start = comment.loc.start;
const end = comment.loc.end;
const isFirstTokenOnLine =
start.line === lineNumber && !line.slice(0, start.column).trim();
const isLastTokenOnLine = end.line === lineNumber && !line.slice(end.column).trim();
return (
comment &&
(start.line < lineNumber || isFirstTokenOnLine) &&
(end.line > lineNumber || isLastTokenOnLine)
);
}
/**
* Identifies is a node is a FunctionExpression which is embedded within a MethodDefinition or Property
* @param {ASTNode} node Node to test
* @returns {boolean} True if it's a FunctionExpression embedded within a MethodDefinition or Property
*/
function isEmbedded(node) {
if (!node.parent) {
return false;
}
if (node !== node.parent.value) {
return false;
}
if (node.parent.type === 'MethodDefinition') {
return true;
}
if (node.parent.type === 'Property') {
return (
node.parent.method === true ||
node.parent.kind === 'get' ||
node.parent.kind === 'set'
);
}
return false;
}
/**
* Count the comments in the function
* @param {ASTNode} funcNode Function AST node
* @returns {void}
* @private
*/
function processFunction(funcNode) {
const node = isEmbedded(funcNode) ? funcNode.parent : funcNode;
let commentCount = 0;
for (let i = node.loc.start.line - 1; i < node.loc.end.line; ++i) {
const line = lines[i];
if (
commentLineNumbers.has(i + 1) &&
isFullLineComment(line, i + 1, commentLineNumbers.get(i + 1))
) {
commentCount++;
}
}
if (commentCount > maxComments) {
const name = astUtils.getFunctionNameWithKind(funcNode);
context.report({
node,
message:
'{{name}} has too many comments ({{commentCount}}). Maximum allowed is {{maxComments}}.',
data: {name, commentCount, maxComments}
});
}
}
//--------------------------------------------------------------------------
// Public API
//--------------------------------------------------------------------------
return {
FunctionDeclaration: processFunction,
FunctionExpression: processFunction,
ArrowFunctionExpression: processFunction
};
}
}
};