UNPKG

5.29 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3const utils_1 = require("@typescript-eslint/utils");
4const util_1 = require("../util");
5exports.default = (0, util_1.createRule)({
6 name: 'consistent-indexed-object-style',
7 meta: {
8 type: 'suggestion',
9 docs: {
10 description: 'Enforce or disallow the use of the record type',
11 // too opinionated to be recommended
12 recommended: false,
13 },
14 messages: {
15 preferRecord: 'A record is preferred over an index signature.',
16 preferIndexSignature: 'An index signature is preferred over a record.',
17 },
18 fixable: 'code',
19 schema: [
20 {
21 enum: ['record', 'index-signature'],
22 },
23 ],
24 },
25 defaultOptions: ['record'],
26 create(context, [mode]) {
27 const sourceCode = context.getSourceCode();
28 function checkMembers(members, node, parentId, prefix, postfix, safeFix = true) {
29 if (members.length !== 1) {
30 return;
31 }
32 const [member] = members;
33 if (member.type !== utils_1.AST_NODE_TYPES.TSIndexSignature) {
34 return;
35 }
36 const [parameter] = member.parameters;
37 if (!parameter) {
38 return;
39 }
40 if (parameter.type !== utils_1.AST_NODE_TYPES.Identifier) {
41 return;
42 }
43 const keyType = parameter.typeAnnotation;
44 if (!keyType) {
45 return;
46 }
47 const valueType = member.typeAnnotation;
48 if (!valueType) {
49 return;
50 }
51 if (parentId) {
52 const scope = context.getScope();
53 const superVar = scope.set.get(parentId.name);
54 if (superVar) {
55 const isCircular = superVar.references.some(item => item.isTypeReference &&
56 node.range[0] <= item.identifier.range[0] &&
57 node.range[1] >= item.identifier.range[1]);
58 if (isCircular) {
59 return;
60 }
61 }
62 }
63 context.report({
64 node,
65 messageId: 'preferRecord',
66 fix: safeFix
67 ? (fixer) => {
68 const key = sourceCode.getText(keyType.typeAnnotation);
69 const value = sourceCode.getText(valueType.typeAnnotation);
70 const record = member.readonly
71 ? `Readonly<Record<${key}, ${value}>>`
72 : `Record<${key}, ${value}>`;
73 return fixer.replaceText(node, `${prefix}${record}${postfix}`);
74 }
75 : null,
76 });
77 }
78 return Object.assign(Object.assign({}, (mode === 'index-signature' && {
79 TSTypeReference(node) {
80 var _a;
81 const typeName = node.typeName;
82 if (typeName.type !== utils_1.AST_NODE_TYPES.Identifier) {
83 return;
84 }
85 if (typeName.name !== 'Record') {
86 return;
87 }
88 const params = (_a = node.typeParameters) === null || _a === void 0 ? void 0 : _a.params;
89 if ((params === null || params === void 0 ? void 0 : params.length) !== 2) {
90 return;
91 }
92 context.report({
93 node,
94 messageId: 'preferIndexSignature',
95 fix(fixer) {
96 const key = sourceCode.getText(params[0]);
97 const type = sourceCode.getText(params[1]);
98 return fixer.replaceText(node, `{ [key: ${key}]: ${type} }`);
99 },
100 });
101 },
102 })), (mode === 'record' && {
103 TSTypeLiteral(node) {
104 const parent = findParentDeclaration(node);
105 checkMembers(node.members, node, parent === null || parent === void 0 ? void 0 : parent.id, '', '');
106 },
107 TSInterfaceDeclaration(node) {
108 var _a, _b, _c, _d;
109 let genericTypes = '';
110 if (((_b = (_a = node.typeParameters) === null || _a === void 0 ? void 0 : _a.params) !== null && _b !== void 0 ? _b : []).length > 0) {
111 genericTypes = `<${(_c = node.typeParameters) === null || _c === void 0 ? void 0 : _c.params.map(p => p.name.name).join(', ')}>`;
112 }
113 checkMembers(node.body.body, node, node.id, `type ${node.id.name}${genericTypes} = `, ';', !((_d = node.extends) === null || _d === void 0 ? void 0 : _d.length));
114 },
115 }));
116 },
117});
118function findParentDeclaration(node) {
119 if (node.parent && node.parent.type !== utils_1.AST_NODE_TYPES.TSTypeAnnotation) {
120 if (node.parent.type === utils_1.AST_NODE_TYPES.TSTypeAliasDeclaration) {
121 return node.parent;
122 }
123 return findParentDeclaration(node.parent);
124 }
125 return undefined;
126}
127//# sourceMappingURL=consistent-indexed-object-style.js.map
\No newline at end of file