eslint-plugin-crisp 1.7.14 → 1.7.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
const EVENT_LISTENERS_SEPARATOR = "--> EVENT LISTENERS <--";
|
|
2
2
|
const EVENT_LISTENER_NAME_PATTERN = /^on[A-Z]/;
|
|
3
|
+
const SEPARATOR_LIKE_PATTERN = /^--> .+ <--$/;
|
|
3
4
|
|
|
4
5
|
export default {
|
|
5
6
|
meta: {
|
|
@@ -10,7 +11,7 @@ export default {
|
|
|
10
11
|
category: "Stylistic Issues",
|
|
11
12
|
recommended: false
|
|
12
13
|
},
|
|
13
|
-
fixable:
|
|
14
|
+
fixable: "code",
|
|
14
15
|
schema: [],
|
|
15
16
|
messages: {
|
|
16
17
|
wrongSection:
|
|
@@ -21,6 +22,13 @@ export default {
|
|
|
21
22
|
create(context) {
|
|
22
23
|
const sourceCode = context.sourceCode;
|
|
23
24
|
|
|
25
|
+
function getLineStart(node) {
|
|
26
|
+
return sourceCode.getIndexFromLoc({
|
|
27
|
+
line: node.loc.start.line,
|
|
28
|
+
column: 0
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
|
|
24
32
|
function getPropertyName(property) {
|
|
25
33
|
if (property.type !== "Property" || property.computed) {
|
|
26
34
|
return null;
|
|
@@ -40,6 +48,188 @@ export default {
|
|
|
40
48
|
return null;
|
|
41
49
|
}
|
|
42
50
|
|
|
51
|
+
function getTopLevelComments(node, properties) {
|
|
52
|
+
return sourceCode.getCommentsInside(node.value).filter((comment) => {
|
|
53
|
+
return !properties.some((property) => {
|
|
54
|
+
return (
|
|
55
|
+
comment.range[0] >= property.range[0] &&
|
|
56
|
+
comment.range[1] <= property.range[1]
|
|
57
|
+
);
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function getMethodBlock(node, property) {
|
|
63
|
+
const comments = sourceCode.getCommentsBefore(property);
|
|
64
|
+
const lastSeparatorIndex = comments.findLastIndex((comment) => {
|
|
65
|
+
return (
|
|
66
|
+
comment.type === "Line" &&
|
|
67
|
+
SEPARATOR_LIKE_PATTERN.test(comment.value.trim())
|
|
68
|
+
);
|
|
69
|
+
});
|
|
70
|
+
const ownedComments = comments.slice(lastSeparatorIndex + 1);
|
|
71
|
+
const firstNode = ownedComments[0] || property;
|
|
72
|
+
const start = getLineStart(firstNode);
|
|
73
|
+
const linePrefix = sourceCode.text.slice(start, firstNode.range[0]);
|
|
74
|
+
|
|
75
|
+
if (linePrefix.trim() !== "") {
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const tokenAfter = sourceCode.getTokenAfter(property);
|
|
80
|
+
const comma = (
|
|
81
|
+
tokenAfter?.value === "," &&
|
|
82
|
+
tokenAfter.range[0] < node.value.range[1]
|
|
83
|
+
)
|
|
84
|
+
? tokenAfter
|
|
85
|
+
: null;
|
|
86
|
+
const propertyEnd = comma?.range[1] || property.range[1];
|
|
87
|
+
const remainingText = sourceCode.text.slice(
|
|
88
|
+
propertyEnd,
|
|
89
|
+
node.value.range[1] - 1
|
|
90
|
+
);
|
|
91
|
+
const nextContentMatch = remainingText.match(/\S/);
|
|
92
|
+
let removalEnd = propertyEnd;
|
|
93
|
+
|
|
94
|
+
if (nextContentMatch) {
|
|
95
|
+
const nextContent = propertyEnd + nextContentMatch.index;
|
|
96
|
+
const nextContentLocation = sourceCode.getLocFromIndex(nextContent);
|
|
97
|
+
|
|
98
|
+
if (nextContentLocation.line > property.loc.end.line) {
|
|
99
|
+
removalEnd = sourceCode.getIndexFromLoc({
|
|
100
|
+
line: nextContentLocation.line,
|
|
101
|
+
column: 0
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return {
|
|
107
|
+
start,
|
|
108
|
+
end: removalEnd,
|
|
109
|
+
text: sourceCode.text.slice(start, property.range[1]).trimEnd()
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
function createMoveFix(node, properties, violations) {
|
|
114
|
+
const topLevelComments = getTopLevelComments(node, properties);
|
|
115
|
+
const eventSeparators = topLevelComments.filter((comment) => {
|
|
116
|
+
return (
|
|
117
|
+
comment.type === "Line" &&
|
|
118
|
+
comment.value.trim() === EVENT_LISTENERS_SEPARATOR
|
|
119
|
+
);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
if (eventSeparators.length > 1) {
|
|
123
|
+
return null;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const eventSeparator = eventSeparators[0] || null;
|
|
127
|
+
const hasSectionAfterEvent = eventSeparator && topLevelComments.some(
|
|
128
|
+
(comment) => {
|
|
129
|
+
return (
|
|
130
|
+
comment.range[0] > eventSeparator.range[1] &&
|
|
131
|
+
comment.type === "Line" &&
|
|
132
|
+
SEPARATOR_LIKE_PATTERN.test(comment.value.trim())
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
);
|
|
136
|
+
|
|
137
|
+
if (hasSectionAfterEvent) {
|
|
138
|
+
return null;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const lastProperty = properties.at(-1);
|
|
142
|
+
const trailingComments = topLevelComments.filter((comment) => {
|
|
143
|
+
return comment.range[0] > lastProperty.range[1];
|
|
144
|
+
});
|
|
145
|
+
const hasUnsafeTrailingComment = trailingComments.some((comment) => {
|
|
146
|
+
return comment !== eventSeparator;
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
if (hasUnsafeTrailingComment) {
|
|
150
|
+
return null;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
const methodBlocks = violations.map(({ property }) => {
|
|
154
|
+
return getMethodBlock(node, property);
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
if (methodBlocks.some((block) => block === null)) {
|
|
158
|
+
return null;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const movedProperties = new Set(
|
|
162
|
+
violations.map(({ property }) => property)
|
|
163
|
+
);
|
|
164
|
+
const remainingProperties = properties.filter((property) => {
|
|
165
|
+
return !movedProperties.has(property);
|
|
166
|
+
});
|
|
167
|
+
const interiorStart = node.value.range[0] + 1;
|
|
168
|
+
const interiorEnd = node.value.range[1] - 1;
|
|
169
|
+
const interiorText = sourceCode.text.slice(interiorStart, interiorEnd);
|
|
170
|
+
const suffixMatch = interiorText.match(/\s*$/);
|
|
171
|
+
const suffix = suffixMatch?.[0] || "";
|
|
172
|
+
const edits = methodBlocks.map((block) => {
|
|
173
|
+
return {
|
|
174
|
+
start: block.start - interiorStart,
|
|
175
|
+
end: block.end - interiorStart,
|
|
176
|
+
text: ""
|
|
177
|
+
};
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
if (remainingProperties.length > 0) {
|
|
181
|
+
const lastRemainingProperty = remainingProperties.at(-1);
|
|
182
|
+
const tokenAfter = sourceCode.getTokenAfter(lastRemainingProperty);
|
|
183
|
+
const hasComma = (
|
|
184
|
+
tokenAfter?.value === "," &&
|
|
185
|
+
tokenAfter.range[0] < interiorEnd
|
|
186
|
+
);
|
|
187
|
+
|
|
188
|
+
if (!hasComma) {
|
|
189
|
+
const propertyEnd = lastRemainingProperty.range[1] - interiorStart;
|
|
190
|
+
|
|
191
|
+
edits.push({
|
|
192
|
+
start: propertyEnd,
|
|
193
|
+
end: propertyEnd,
|
|
194
|
+
text: ","
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const transformedText = [...edits]
|
|
200
|
+
.sort((first, second) => {
|
|
201
|
+
return second.start - first.start || second.end - first.end;
|
|
202
|
+
})
|
|
203
|
+
.reduce((text, edit) => {
|
|
204
|
+
return (
|
|
205
|
+
text.slice(0, edit.start) +
|
|
206
|
+
edit.text +
|
|
207
|
+
text.slice(edit.end)
|
|
208
|
+
);
|
|
209
|
+
}, interiorText)
|
|
210
|
+
.trimEnd();
|
|
211
|
+
const movedText = methodBlocks
|
|
212
|
+
.map((block) => block.text)
|
|
213
|
+
.join(",\n\n");
|
|
214
|
+
const methodIndent = movedText.match(/^[\t ]*/)?.[0] || "";
|
|
215
|
+
const sectionText = eventSeparator
|
|
216
|
+
? movedText
|
|
217
|
+
: (
|
|
218
|
+
`${methodIndent}// ${EVENT_LISTENERS_SEPARATOR}\n\n` +
|
|
219
|
+
movedText
|
|
220
|
+
);
|
|
221
|
+
const fixedInterior = transformedText === ""
|
|
222
|
+
? `\n${sectionText}${suffix}`
|
|
223
|
+
: `${transformedText}\n\n${sectionText}${suffix}`;
|
|
224
|
+
|
|
225
|
+
return (fixer) => {
|
|
226
|
+
return fixer.replaceTextRange(
|
|
227
|
+
[interiorStart, interiorEnd],
|
|
228
|
+
fixedInterior
|
|
229
|
+
);
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
|
|
43
233
|
function checkMethods(node) {
|
|
44
234
|
const properties = node.value.properties;
|
|
45
235
|
|
|
@@ -48,6 +238,7 @@ export default {
|
|
|
48
238
|
}
|
|
49
239
|
|
|
50
240
|
let eventListenersStarted = false;
|
|
241
|
+
const violations = [];
|
|
51
242
|
|
|
52
243
|
properties.forEach((property) => {
|
|
53
244
|
const comments = sourceCode.getCommentsBefore(property);
|
|
@@ -68,13 +259,25 @@ export default {
|
|
|
68
259
|
const name = getPropertyName(property);
|
|
69
260
|
|
|
70
261
|
if (name && EVENT_LISTENER_NAME_PATTERN.test(name)) {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
data: { name }
|
|
262
|
+
violations.push({
|
|
263
|
+
property,
|
|
264
|
+
name
|
|
75
265
|
});
|
|
76
266
|
}
|
|
77
267
|
});
|
|
268
|
+
|
|
269
|
+
const moveFix = violations.length > 0
|
|
270
|
+
? createMoveFix(node, properties, violations)
|
|
271
|
+
: null;
|
|
272
|
+
|
|
273
|
+
violations.forEach(({ property, name }, index) => {
|
|
274
|
+
context.report({
|
|
275
|
+
node: property.key,
|
|
276
|
+
messageId: "wrongSection",
|
|
277
|
+
data: { name },
|
|
278
|
+
...(index === 0 && moveFix ? { fix: moveFix } : {})
|
|
279
|
+
});
|
|
280
|
+
});
|
|
78
281
|
}
|
|
79
282
|
|
|
80
283
|
return {
|
|
@@ -72,6 +72,34 @@ ruleTester.run("vue-event-listener-section", rule, {
|
|
|
72
72
|
export default {
|
|
73
73
|
methods: {
|
|
74
74
|
// --> ACTIONS <--
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Saves content
|
|
78
|
+
*/
|
|
79
|
+
save() {},
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Triggers on save
|
|
83
|
+
*/
|
|
84
|
+
onSave() {}
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
`,
|
|
88
|
+
output: `
|
|
89
|
+
export default {
|
|
90
|
+
methods: {
|
|
91
|
+
// --> ACTIONS <--
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Saves content
|
|
95
|
+
*/
|
|
96
|
+
save() {},
|
|
97
|
+
|
|
98
|
+
// --> EVENT LISTENERS <--
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Triggers on save
|
|
102
|
+
*/
|
|
75
103
|
onSave() {}
|
|
76
104
|
}
|
|
77
105
|
};
|
|
@@ -88,6 +116,22 @@ ruleTester.run("vue-event-listener-section", rule, {
|
|
|
88
116
|
export default {
|
|
89
117
|
methods: {
|
|
90
118
|
// --> HELPERS <--
|
|
119
|
+
|
|
120
|
+
format() {},
|
|
121
|
+
|
|
122
|
+
onLoadMore() {}
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
`,
|
|
126
|
+
output: `
|
|
127
|
+
export default {
|
|
128
|
+
methods: {
|
|
129
|
+
// --> HELPERS <--
|
|
130
|
+
|
|
131
|
+
format() {},
|
|
132
|
+
|
|
133
|
+
// --> EVENT LISTENERS <--
|
|
134
|
+
|
|
91
135
|
onLoadMore() {}
|
|
92
136
|
}
|
|
93
137
|
};
|
|
@@ -107,6 +151,15 @@ ruleTester.run("vue-event-listener-section", rule, {
|
|
|
107
151
|
}
|
|
108
152
|
};
|
|
109
153
|
`,
|
|
154
|
+
output: `
|
|
155
|
+
export default {
|
|
156
|
+
methods: {
|
|
157
|
+
// --> EVENT LISTENERS <--
|
|
158
|
+
|
|
159
|
+
"onClose": function() {}
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
`,
|
|
110
163
|
errors: [
|
|
111
164
|
{
|
|
112
165
|
messageId: "wrongSection",
|
|
@@ -121,15 +174,45 @@ ruleTester.run("vue-event-listener-section", rule, {
|
|
|
121
174
|
export default defineComponent({
|
|
122
175
|
methods: {
|
|
123
176
|
// --> ACTIONS <--
|
|
177
|
+
|
|
178
|
+
save() {},
|
|
179
|
+
|
|
124
180
|
onSave() {},
|
|
125
181
|
// --> HELPERS <--
|
|
182
|
+
|
|
183
|
+
format() {},
|
|
184
|
+
|
|
126
185
|
onFormatComplete() {},
|
|
127
186
|
// --> EVENT LISTENERS <--
|
|
187
|
+
|
|
128
188
|
onClose() {}
|
|
129
189
|
}
|
|
130
190
|
});
|
|
131
191
|
</script>
|
|
132
192
|
`,
|
|
193
|
+
output: `
|
|
194
|
+
<script>
|
|
195
|
+
export default defineComponent({
|
|
196
|
+
methods: {
|
|
197
|
+
// --> ACTIONS <--
|
|
198
|
+
|
|
199
|
+
save() {},
|
|
200
|
+
|
|
201
|
+
// --> HELPERS <--
|
|
202
|
+
|
|
203
|
+
format() {},
|
|
204
|
+
|
|
205
|
+
// --> EVENT LISTENERS <--
|
|
206
|
+
|
|
207
|
+
onClose() {},
|
|
208
|
+
|
|
209
|
+
onSave() {},
|
|
210
|
+
|
|
211
|
+
onFormatComplete() {}
|
|
212
|
+
}
|
|
213
|
+
});
|
|
214
|
+
</script>
|
|
215
|
+
`,
|
|
133
216
|
errors: [
|
|
134
217
|
{
|
|
135
218
|
messageId: "wrongSection",
|