-
-
Notifications
You must be signed in to change notification settings - Fork 2.7k
/
class-literal-property-style.ts
128 lines (107 loc) · 3.32 KB
/
class-literal-property-style.ts
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
import { AST_NODE_TYPES, TSESTree } from '@typescript-eslint/utils';
import * as util from '../util';
type Options = ['fields' | 'getters'];
type MessageIds = 'preferFieldStyle' | 'preferGetterStyle';
interface NodeWithModifiers {
accessibility?: TSESTree.Accessibility;
static: boolean;
}
const printNodeModifiers = (
node: NodeWithModifiers,
final: 'readonly' | 'get',
): string =>
`${node.accessibility ?? ''}${
node.static ? ' static' : ''
} ${final} `.trimStart();
const isSupportedLiteral = (
node: TSESTree.Node,
): node is TSESTree.LiteralExpression => {
if (node.type === AST_NODE_TYPES.Literal) {
return true;
}
if (
node.type === AST_NODE_TYPES.TaggedTemplateExpression ||
node.type === AST_NODE_TYPES.TemplateLiteral
) {
return ('quasi' in node ? node.quasi.quasis : node.quasis).length === 1;
}
return false;
};
export default util.createRule<Options, MessageIds>({
name: 'class-literal-property-style',
meta: {
type: 'problem',
docs: {
description:
'Enforce that literals on classes are exposed in a consistent style',
recommended: 'strict',
},
fixable: 'code',
messages: {
preferFieldStyle: 'Literals should be exposed using readonly fields.',
preferGetterStyle: 'Literals should be exposed using getters.',
},
schema: [{ enum: ['fields', 'getters'] }],
},
defaultOptions: ['fields'],
create(context, [style]) {
return {
...(style === 'fields' && {
MethodDefinition(node): void {
if (
node.kind !== 'get' ||
!node.value.body ||
!node.value.body.body.length
) {
return;
}
const [statement] = node.value.body.body;
if (statement.type !== AST_NODE_TYPES.ReturnStatement) {
return;
}
const { argument } = statement;
if (!argument || !isSupportedLiteral(argument)) {
return;
}
context.report({
node: node.key,
messageId: 'preferFieldStyle',
fix(fixer) {
const sourceCode = context.getSourceCode();
const name = sourceCode.getText(node.key);
let text = '';
text += printNodeModifiers(node, 'readonly');
text += node.computed ? `[${name}]` : name;
text += ` = ${sourceCode.getText(argument)};`;
return fixer.replaceText(node, text);
},
});
},
}),
...(style === 'getters' && {
PropertyDefinition(node): void {
if (!node.readonly || node.declare) {
return;
}
const { value } = node;
if (!value || !isSupportedLiteral(value)) {
return;
}
context.report({
node: node.key,
messageId: 'preferGetterStyle',
fix(fixer) {
const sourceCode = context.getSourceCode();
const name = sourceCode.getText(node.key);
let text = '';
text += printNodeModifiers(node, 'get');
text += node.computed ? `[${name}]` : name;
text += `() { return ${sourceCode.getText(value)}; }`;
return fixer.replaceText(node, text);
},
});
},
}),
};
},
});