UNPKG

10.9 kBJavaScriptView Raw
1"use strict";
2var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3 if (k2 === undefined) k2 = k;
4 Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
5}) : (function(o, m, k, k2) {
6 if (k2 === undefined) k2 = k;
7 o[k2] = m[k];
8}));
9var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
10 Object.defineProperty(o, "default", { enumerable: true, value: v });
11}) : function(o, v) {
12 o["default"] = v;
13});
14var __importStar = (this && this.__importStar) || function (mod) {
15 if (mod && mod.__esModule) return mod;
16 var result = {};
17 if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
18 __setModuleDefault(result, mod);
19 return result;
20};
21Object.defineProperty(exports, "__esModule", { value: true });
22const utils_1 = require("@typescript-eslint/utils");
23const util = __importStar(require("../util"));
24const enumValues = [
25 'always',
26 'never',
27 'in-unions',
28 'in-intersections',
29 'in-unions-and-intersections',
30];
31exports.default = util.createRule({
32 name: 'no-type-alias',
33 meta: {
34 type: 'suggestion',
35 docs: {
36 description: 'Disallow the use of type aliases',
37 // too opinionated to be recommended
38 recommended: false,
39 },
40 messages: {
41 noTypeAlias: 'Type {{alias}} are not allowed.',
42 noCompositionAlias: '{{typeName}} in {{compositionType}} types are not allowed.',
43 },
44 schema: [
45 {
46 type: 'object',
47 properties: {
48 allowAliases: {
49 enum: enumValues,
50 },
51 allowCallbacks: {
52 enum: ['always', 'never'],
53 },
54 allowConditionalTypes: {
55 enum: ['always', 'never'],
56 },
57 allowConstructors: {
58 enum: ['always', 'never'],
59 },
60 allowLiterals: {
61 enum: enumValues,
62 },
63 allowMappedTypes: {
64 enum: enumValues,
65 },
66 allowTupleTypes: {
67 enum: enumValues,
68 },
69 allowGenerics: {
70 enum: ['always', 'never'],
71 },
72 },
73 additionalProperties: false,
74 },
75 ],
76 },
77 defaultOptions: [
78 {
79 allowAliases: 'never',
80 allowCallbacks: 'never',
81 allowConditionalTypes: 'never',
82 allowConstructors: 'never',
83 allowLiterals: 'never',
84 allowMappedTypes: 'never',
85 allowTupleTypes: 'never',
86 allowGenerics: 'never',
87 },
88 ],
89 create(context, [{ allowAliases, allowCallbacks, allowConditionalTypes, allowConstructors, allowLiterals, allowMappedTypes, allowTupleTypes, allowGenerics, },]) {
90 const unions = ['always', 'in-unions', 'in-unions-and-intersections'];
91 const intersections = [
92 'always',
93 'in-intersections',
94 'in-unions-and-intersections',
95 ];
96 const compositions = [
97 'in-unions',
98 'in-intersections',
99 'in-unions-and-intersections',
100 ];
101 const aliasTypes = new Set([
102 utils_1.AST_NODE_TYPES.TSArrayType,
103 utils_1.AST_NODE_TYPES.TSImportType,
104 utils_1.AST_NODE_TYPES.TSTypeReference,
105 utils_1.AST_NODE_TYPES.TSLiteralType,
106 utils_1.AST_NODE_TYPES.TSTypeQuery,
107 utils_1.AST_NODE_TYPES.TSIndexedAccessType,
108 ]);
109 /**
110 * Determines if the composition type is supported by the allowed flags.
111 * @param isTopLevel a flag indicating this is the top level node.
112 * @param compositionType the composition type (either TSUnionType or TSIntersectionType)
113 * @param allowed the currently allowed flags.
114 */
115 function isSupportedComposition(isTopLevel, compositionType, allowed) {
116 return (!compositions.includes(allowed) ||
117 (!isTopLevel &&
118 ((compositionType === utils_1.AST_NODE_TYPES.TSUnionType &&
119 unions.includes(allowed)) ||
120 (compositionType === utils_1.AST_NODE_TYPES.TSIntersectionType &&
121 intersections.includes(allowed)))));
122 }
123 /**
124 * Gets the message to be displayed based on the node type and whether the node is a top level declaration.
125 * @param node the location
126 * @param compositionType the type of composition this alias is part of (undefined if not
127 * part of a composition)
128 * @param isRoot a flag indicating we are dealing with the top level declaration.
129 * @param type the kind of type alias being validated.
130 */
131 function reportError(node, compositionType, isRoot, type) {
132 if (isRoot) {
133 return context.report({
134 node,
135 messageId: 'noTypeAlias',
136 data: {
137 alias: type.toLowerCase(),
138 },
139 });
140 }
141 return context.report({
142 node,
143 messageId: 'noCompositionAlias',
144 data: {
145 compositionType: compositionType === utils_1.AST_NODE_TYPES.TSUnionType
146 ? 'union'
147 : 'intersection',
148 typeName: type,
149 },
150 });
151 }
152 const isValidTupleType = (type) => {
153 if (type.node.type === utils_1.AST_NODE_TYPES.TSTupleType) {
154 return true;
155 }
156 if (type.node.type === utils_1.AST_NODE_TYPES.TSTypeOperator) {
157 if (['keyof', 'readonly'].includes(type.node.operator) &&
158 type.node.typeAnnotation &&
159 type.node.typeAnnotation.type === utils_1.AST_NODE_TYPES.TSTupleType) {
160 return true;
161 }
162 }
163 return false;
164 };
165 const isValidGeneric = (type) => {
166 return (type.node.type === utils_1.AST_NODE_TYPES.TSTypeReference &&
167 type.node.typeParameters !== undefined);
168 };
169 const checkAndReport = (optionValue, isTopLevel, type, label) => {
170 if (optionValue === 'never' ||
171 !isSupportedComposition(isTopLevel, type.compositionType, optionValue)) {
172 reportError(type.node, type.compositionType, isTopLevel, label);
173 }
174 };
175 /**
176 * Validates the node looking for aliases, callbacks and literals.
177 * @param type the type of composition this alias is part of (null if not
178 * part of a composition)
179 * @param isTopLevel a flag indicating this is the top level node.
180 */
181 function validateTypeAliases(type, isTopLevel = false) {
182 if (type.node.type === utils_1.AST_NODE_TYPES.TSFunctionType) {
183 // callback
184 if (allowCallbacks === 'never') {
185 reportError(type.node, type.compositionType, isTopLevel, 'Callbacks');
186 }
187 }
188 else if (type.node.type === utils_1.AST_NODE_TYPES.TSConditionalType) {
189 // conditional type
190 if (allowConditionalTypes === 'never') {
191 reportError(type.node, type.compositionType, isTopLevel, 'Conditional types');
192 }
193 }
194 else if (type.node.type === utils_1.AST_NODE_TYPES.TSConstructorType) {
195 if (allowConstructors === 'never') {
196 reportError(type.node, type.compositionType, isTopLevel, 'Constructors');
197 }
198 }
199 else if (type.node.type === utils_1.AST_NODE_TYPES.TSTypeLiteral) {
200 // literal object type
201 checkAndReport(allowLiterals, isTopLevel, type, 'Literals');
202 }
203 else if (type.node.type === utils_1.AST_NODE_TYPES.TSMappedType) {
204 // mapped type
205 checkAndReport(allowMappedTypes, isTopLevel, type, 'Mapped types');
206 }
207 else if (isValidTupleType(type)) {
208 // tuple types
209 checkAndReport(allowTupleTypes, isTopLevel, type, 'Tuple Types');
210 }
211 else if (isValidGeneric(type)) {
212 if (allowGenerics === 'never') {
213 reportError(type.node, type.compositionType, isTopLevel, 'Generics');
214 }
215 }
216 else if (type.node.type.endsWith(utils_1.AST_TOKEN_TYPES.Keyword) ||
217 aliasTypes.has(type.node.type) ||
218 (type.node.type === utils_1.AST_NODE_TYPES.TSTypeOperator &&
219 (type.node.operator === 'keyof' ||
220 (type.node.operator === 'readonly' &&
221 type.node.typeAnnotation &&
222 aliasTypes.has(type.node.typeAnnotation.type))))) {
223 // alias / keyword
224 checkAndReport(allowAliases, isTopLevel, type, 'Aliases');
225 }
226 else {
227 // unhandled type - shouldn't happen
228 reportError(type.node, type.compositionType, isTopLevel, 'Unhandled');
229 }
230 }
231 /**
232 * Flatten the given type into an array of its dependencies
233 */
234 function getTypes(node, compositionType = null) {
235 if (node.type === utils_1.AST_NODE_TYPES.TSUnionType ||
236 node.type === utils_1.AST_NODE_TYPES.TSIntersectionType) {
237 return node.types.reduce((acc, type) => {
238 acc.push(...getTypes(type, node.type));
239 return acc;
240 }, []);
241 }
242 return [{ node, compositionType }];
243 }
244 return {
245 TSTypeAliasDeclaration(node) {
246 const types = getTypes(node.typeAnnotation);
247 if (types.length === 1) {
248 // is a top level type annotation
249 validateTypeAliases(types[0], true);
250 }
251 else {
252 // is a composition type
253 types.forEach(type => {
254 validateTypeAliases(type);
255 });
256 }
257 },
258 };
259 },
260});
261//# sourceMappingURL=no-type-alias.js.map
\No newline at end of file