-
-
Notifications
You must be signed in to change notification settings - Fork 10
Expand file tree
/
Copy pathprefer-slice-over-split-index.ts
More file actions
80 lines (74 loc) · 2.72 KB
/
Copy pathprefer-slice-over-split-index.ts
File metadata and controls
80 lines (74 loc) · 2.72 KB
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
import type {
CallExpression,
Expression,
MemberExpression,
SpreadElement
} from 'estree';
import type {Rule} from 'eslint';
function stringValue(node: Expression | SpreadElement): string | null {
if (node.type === 'Literal') {
return typeof node.value === 'string' ? node.value : null;
}
if (node.type === 'TemplateLiteral' && node.expressions.length === 0) {
const cooked = node.quasis[0]?.value.cooked;
return typeof cooked === 'string' ? cooked : null;
}
return null;
}
function isSupportedLimit(
limit: Expression | SpreadElement | undefined,
index: 0 | 1
): boolean {
if (!limit) return true;
if (limit.type !== 'Literal') return false;
const {value} = limit;
return typeof value === 'number' && Number.isInteger(value) && value > index;
}
function getSplitCall(node: MemberExpression): CallExpression | null {
const call = node.object;
if (call.type !== 'CallExpression') return null;
const callee = call.callee;
if (callee.type !== 'MemberExpression' || callee.computed) return null;
if (callee.property.type !== 'Identifier' || callee.property.name !== 'split')
return null;
if (call.arguments.length === 0 || call.arguments.length > 2) return null;
const separator = call.arguments[0];
if (!separator) return null;
const value = stringValue(separator);
if (value === null || value.length === 0) return null;
return call;
}
export const preferSliceOverSplitIndex: Rule.RuleModule = {
meta: {
type: 'suggestion',
docs: {
description:
'Prefer `indexOf(needle)` and `slice(...)` over `split()[N]` when splitting a string into two pieces.',
recommended: false
},
schema: [],
messages: {
preferSliceFirst:
'Prefer `indexOf(needle)` and `slice(0, index)` over `split(needle)[0]` for string separators. `split` will allocate an intermediate array, resulting in poorer performance. Preserve the missing-separator fallback explicitly.',
preferSliceSecond:
'Prefer `indexOf(needle)` and `slice(index)` over `split(needle)[1]` for string separators. `split` will allocate an intermediate array, resulting in poorer performance. Preserve the missing-separator fallback explicitly.'
}
},
create(context) {
return {
MemberExpression(node: MemberExpression) {
if (!node.computed) return;
if (node.property.type !== 'Literal') return;
const index = node.property.value;
if (index !== 0 && index !== 1) return;
const call = getSplitCall(node);
if (!call) return;
if (!isSupportedLimit(call.arguments[1], index)) return;
context.report({
node,
messageId: index === 0 ? 'preferSliceFirst' : 'preferSliceSecond'
});
}
};
}
};