-
-
Notifications
You must be signed in to change notification settings - Fork 153
/
delimiterDangle.js
142 lines (113 loc) · 3.08 KB
/
delimiterDangle.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
import _ from 'lodash';
const schema = [
{
enum: ['always', 'always-multiline', 'only-multiline', 'never'],
type: 'string',
},
{
enum: ['always', 'always-multiline', 'only-multiline', 'never'],
type: 'string',
},
{
enum: ['always', 'always-multiline', 'only-multiline', 'never'],
type: 'string',
},
];
// required for reporting the correct position
const getLast = (property, indexer) => {
if (!property) {
return indexer;
}
if (!indexer) {
return property;
}
if (property.loc.end.line > indexer.loc.end.line) {
return property;
}
if (indexer.loc.end.line > property.loc.end.line) {
return indexer;
}
if (property.loc.end.column > indexer.loc.end.column) {
return property;
}
return indexer;
};
const create = (context) => {
const option = context.options[0] || 'never';
const interfaceOption = context.options[1] || option;
const inexactNotationOption = context.options[2] || 'never';
const sourceCode = context.getSourceCode();
const getNodeOption = (node) => {
if (node.parent.type === 'InterfaceDeclaration') {
return interfaceOption;
}
if (node.inexact) {
return inexactNotationOption;
}
return option;
};
const reporter = (node, message, fix) => {
return () => {
context.report({
fix,
message,
node,
});
};
};
const makeReporters = (node, tokenToFix) => {
return {
dangle: reporter(node, 'Unexpected trailing delimiter', (fixer) => {
return fixer.replaceText(tokenToFix, '');
}),
noDangle: reporter(node, 'Missing trailing delimiter', (fixer) => {
return fixer.insertTextAfter(tokenToFix, ',');
}),
};
};
const evaluate = (node, lastChildNode) => {
if (!lastChildNode && !node.inexact) {
return;
}
const [penultimateToken, lastToken] = sourceCode.getLastTokens(node, 2);
const isDangling = [';', ','].includes(penultimateToken.value);
const isMultiLine = penultimateToken.loc.start.line !== lastToken.loc.start.line;
// Use the object node if it's inexact since there's no child node for the inexact notation
const report = makeReporters(node.inexact ? node : lastChildNode, penultimateToken);
const nodeOption = getNodeOption(node);
if (nodeOption === 'always' && !isDangling) {
report.noDangle();
return;
}
if (nodeOption === 'never' && isDangling) {
report.dangle();
return;
}
if (nodeOption === 'always-multiline' && !isDangling && isMultiLine) {
report.noDangle();
return;
}
if (nodeOption === 'always-multiline' && isDangling && !isMultiLine) {
report.dangle();
return;
}
if (nodeOption === 'only-multiline' && isDangling && !isMultiLine) {
report.dangle();
}
};
return {
ObjectTypeAnnotation (node) {
evaluate(node, getLast(_.last(node.properties), _.last(node.indexers)));
},
TupleTypeAnnotation (node) {
evaluate(node, _.last(node.types));
},
};
};
export default {
create,
meta: {
fixable: 'code',
},
schema,
};