-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
/
Copy pathnewline-after-import.js
108 lines (88 loc) · 3.05 KB
/
newline-after-import.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
/**
* @fileoverview Rule to enforce new line after import not followed by another import.
* @author Radek Benkel
*/
import isStaticRequire from '../core/staticRequire'
import findIndex from 'lodash.findindex'
//------------------------------------------------------------------------------
// Rule Definition
//------------------------------------------------------------------------------
function containsNodeOrEqual(outerNode, innerNode) {
return outerNode.range[0] <= innerNode.range[0] && outerNode.range[1] >= innerNode.range[1]
}
function getScopeBody(scope) {
const { body } = scope.block
if (body.type === 'BlockStatement') {
return body.body
}
return body
}
function findNodeIndexInScopeBody(scope, nodeToFind) {
const body = getScopeBody(scope)
return findIndex(body, (node) => containsNodeOrEqual(node, nodeToFind))
}
function getLineDifference(node, nextNode) {
return nextNode.loc.start.line - node.loc.end.line
}
module.exports = function (context) {
const scopes = []
let scopeIndex = 0
function checkForNewLine(node, nextNode, type) {
if (getLineDifference(node, nextNode) < 2) {
let column = node.loc.start.column
if (node.loc.start.line !== node.loc.end.line) {
column = 0
}
context.report({
loc: {
line: node.loc.end.line,
column,
},
message: `Expected empty line after ${type} statement not followed by another ${type}.`,
})
}
}
return {
ImportDeclaration: function (node) {
const { parent } = node
const nodePosition = parent.body.indexOf(node)
const nextNode = parent.body[nodePosition + 1]
if (nextNode && nextNode.type !== 'ImportDeclaration') {
checkForNewLine(node, nextNode, 'import')
}
},
Program: function () {
scopes.push({ scope: context.getScope(), requireCalls: [] })
},
CallExpression: function(node) {
const scope = context.getScope()
if (isStaticRequire(node)) {
const currentScope = scopes[scopeIndex]
if (scope === currentScope.scope) {
currentScope.requireCalls.push(node)
} else {
scopes.push({ scope, requireCalls: [ node ] })
scopeIndex += 1
}
}
},
'Program:exit': function () {
scopes.forEach(function ({ scope, requireCalls }) {
requireCalls.forEach(function (node, index) {
const scopeBody = getScopeBody(scope)
const nodePosition = findNodeIndexInScopeBody(scope, node)
const statementWithRequireCall = scopeBody[nodePosition]
const nextStatement = scopeBody[nodePosition + 1]
const nextRequireCall = requireCalls[index + 1]
if (nextRequireCall && containsNodeOrEqual(statementWithRequireCall, nextRequireCall)) {
return
}
if (nextStatement &&
(!nextRequireCall || !containsNodeOrEqual(nextStatement, nextRequireCall))) {
checkForNewLine(statementWithRequireCall, nextStatement, 'require')
}
})
})
},
}
}