UNPKG

31.7 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"));
24function isImportToken(token) {
25 return token.type === utils_1.AST_TOKEN_TYPES.Keyword && token.value === 'import';
26}
27function isTypeToken(token) {
28 return token.type === utils_1.AST_TOKEN_TYPES.Identifier && token.value === 'type';
29}
30exports.default = util.createRule({
31 name: 'consistent-type-imports',
32 meta: {
33 type: 'suggestion',
34 docs: {
35 description: 'Enforces consistent usage of type imports',
36 recommended: false,
37 },
38 messages: {
39 typeOverValue: 'All imports in the declaration are only used as types. Use `import type`.',
40 someImportsAreOnlyTypes: 'Imports {{typeImports}} are only used as types.',
41 aImportIsOnlyTypes: 'Import {{typeImports}} is only used as types.',
42 someImportsInDecoMeta: 'Type imports {{typeImports}} are used by decorator metadata.',
43 aImportInDecoMeta: 'Type import {{typeImports}} is used by decorator metadata.',
44 valueOverType: 'Use an `import` instead of an `import type`.',
45 noImportTypeAnnotations: '`import()` type annotations are forbidden.',
46 },
47 schema: [
48 {
49 type: 'object',
50 properties: {
51 prefer: {
52 enum: ['type-imports', 'no-type-imports'],
53 },
54 disallowTypeAnnotations: {
55 type: 'boolean',
56 },
57 },
58 additionalProperties: false,
59 },
60 ],
61 fixable: 'code',
62 },
63 defaultOptions: [
64 {
65 prefer: 'type-imports',
66 disallowTypeAnnotations: true,
67 },
68 ],
69 create(context, [option]) {
70 var _a;
71 const prefer = (_a = option.prefer) !== null && _a !== void 0 ? _a : 'type-imports';
72 const disallowTypeAnnotations = option.disallowTypeAnnotations !== false;
73 const sourceCode = context.getSourceCode();
74 const sourceImportsMap = {};
75 return Object.assign(Object.assign({}, (prefer === 'type-imports'
76 ? {
77 // prefer type imports
78 ImportDeclaration(node) {
79 var _a;
80 const source = node.source.value;
81 const sourceImports = (_a = sourceImportsMap[source]) !== null && _a !== void 0 ? _a : (sourceImportsMap[source] = {
82 source,
83 reportValueImports: [],
84 typeOnlyNamedImport: null,
85 valueOnlyNamedImport: null,
86 });
87 if (node.importKind === 'type') {
88 if (!sourceImports.typeOnlyNamedImport &&
89 node.specifiers.every(specifier => specifier.type === utils_1.AST_NODE_TYPES.ImportSpecifier)) {
90 sourceImports.typeOnlyNamedImport = node;
91 }
92 }
93 else {
94 if (!sourceImports.valueOnlyNamedImport &&
95 node.specifiers.every(specifier => specifier.type === utils_1.AST_NODE_TYPES.ImportSpecifier)) {
96 sourceImports.valueOnlyNamedImport = node;
97 }
98 }
99 const typeSpecifiers = [];
100 const inlineTypeSpecifiers = [];
101 const valueSpecifiers = [];
102 const unusedSpecifiers = [];
103 for (const specifier of node.specifiers) {
104 if (specifier.type === utils_1.AST_NODE_TYPES.ImportSpecifier &&
105 specifier.importKind === 'type') {
106 inlineTypeSpecifiers.push(specifier);
107 continue;
108 }
109 const [variable] = context.getDeclaredVariables(specifier);
110 if (variable.references.length === 0) {
111 unusedSpecifiers.push(specifier);
112 }
113 else {
114 const onlyHasTypeReferences = variable.references.every(ref => {
115 var _a, _b;
116 /**
117 * keep origin import kind when export
118 * export { Type }
119 * export default Type;
120 */
121 if (((_a = ref.identifier.parent) === null || _a === void 0 ? void 0 : _a.type) ===
122 utils_1.AST_NODE_TYPES.ExportSpecifier ||
123 ((_b = ref.identifier.parent) === null || _b === void 0 ? void 0 : _b.type) ===
124 utils_1.AST_NODE_TYPES.ExportDefaultDeclaration) {
125 if (ref.isValueReference && ref.isTypeReference) {
126 return node.importKind === 'type';
127 }
128 }
129 if (ref.isValueReference) {
130 let parent = ref.identifier.parent;
131 let child = ref.identifier;
132 while (parent) {
133 switch (parent.type) {
134 // CASE 1:
135 // `type T = typeof foo` will create a value reference because "foo" must be a value type
136 // however this value reference is safe to use with type-only imports
137 case utils_1.AST_NODE_TYPES.TSTypeQuery:
138 return true;
139 case utils_1.AST_NODE_TYPES.TSQualifiedName:
140 // TSTypeQuery must have a TSESTree.EntityName as its child, so we can filter here and break early
141 if (parent.left !== child) {
142 return false;
143 }
144 child = parent;
145 parent = parent.parent;
146 continue;
147 // END CASE 1
148 //////////////
149 // CASE 2:
150 // `type T = { [foo]: string }` will create a value reference because "foo" must be a value type
151 // however this value reference is safe to use with type-only imports.
152 // Also this is represented as a non-type AST - hence it uses MemberExpression
153 case utils_1.AST_NODE_TYPES.TSPropertySignature:
154 return parent.key === child;
155 case utils_1.AST_NODE_TYPES.MemberExpression:
156 if (parent.object !== child) {
157 return false;
158 }
159 child = parent;
160 parent = parent.parent;
161 continue;
162 // END CASE 2
163 default:
164 return false;
165 }
166 }
167 }
168 return ref.isTypeReference;
169 });
170 if (onlyHasTypeReferences) {
171 typeSpecifiers.push(specifier);
172 }
173 else {
174 valueSpecifiers.push(specifier);
175 }
176 }
177 }
178 if ((node.importKind === 'value' && typeSpecifiers.length) ||
179 (node.importKind === 'type' && valueSpecifiers.length)) {
180 sourceImports.reportValueImports.push({
181 node,
182 typeSpecifiers,
183 valueSpecifiers,
184 unusedSpecifiers,
185 inlineTypeSpecifiers,
186 });
187 }
188 },
189 'Program:exit'() {
190 for (const sourceImports of Object.values(sourceImportsMap)) {
191 if (sourceImports.reportValueImports.length === 0) {
192 continue;
193 }
194 for (const report of sourceImports.reportValueImports) {
195 if (report.valueSpecifiers.length === 0 &&
196 report.unusedSpecifiers.length === 0) {
197 // import is all type-only, convert the entire import to `import type`
198 context.report({
199 node: report.node,
200 messageId: 'typeOverValue',
201 *fix(fixer) {
202 yield* fixToTypeImportDeclaration(fixer, report, sourceImports);
203 },
204 });
205 }
206 else {
207 const isTypeImport = report.node.importKind === 'type';
208 // we have a mixed type/value import, so we need to split them out into multiple exports
209 const importNames = (isTypeImport
210 ? report.valueSpecifiers
211 : report.typeSpecifiers).map(specifier => `"${specifier.local.name}"`);
212 const message = (() => {
213 const typeImports = util.formatWordList(importNames);
214 if (importNames.length === 1) {
215 if (isTypeImport) {
216 return {
217 messageId: 'aImportInDecoMeta',
218 data: { typeImports },
219 };
220 }
221 else {
222 return {
223 messageId: 'aImportIsOnlyTypes',
224 data: { typeImports },
225 };
226 }
227 }
228 else {
229 if (isTypeImport) {
230 return {
231 messageId: 'someImportsInDecoMeta',
232 data: { typeImports },
233 };
234 }
235 else {
236 return {
237 messageId: 'someImportsAreOnlyTypes',
238 data: { typeImports },
239 };
240 }
241 }
242 })();
243 context.report(Object.assign(Object.assign({ node: report.node }, message), { *fix(fixer) {
244 if (isTypeImport) {
245 yield* fixToValueImportDeclaration(fixer, report, sourceImports);
246 }
247 else {
248 yield* fixToTypeImportDeclaration(fixer, report, sourceImports);
249 }
250 } }));
251 }
252 }
253 }
254 },
255 }
256 : {
257 // prefer no type imports
258 'ImportDeclaration[importKind = "type"]'(node) {
259 context.report({
260 node,
261 messageId: 'valueOverType',
262 fix(fixer) {
263 return fixRemoveTypeSpecifierFromImportDeclaration(fixer, node);
264 },
265 });
266 },
267 'ImportSpecifier[importKind = "type"]'(node) {
268 context.report({
269 node,
270 messageId: 'valueOverType',
271 fix(fixer) {
272 return fixRemoveTypeSpecifierFromImportSpecifier(fixer, node);
273 },
274 });
275 },
276 })), (disallowTypeAnnotations
277 ? {
278 // disallow `import()` type
279 TSImportType(node) {
280 context.report({
281 node,
282 messageId: 'noImportTypeAnnotations',
283 });
284 },
285 }
286 : {}));
287 function classifySpecifier(node) {
288 var _a;
289 const defaultSpecifier = node.specifiers[0].type === utils_1.AST_NODE_TYPES.ImportDefaultSpecifier
290 ? node.specifiers[0]
291 : null;
292 const namespaceSpecifier = (_a = node.specifiers.find((specifier) => specifier.type === utils_1.AST_NODE_TYPES.ImportNamespaceSpecifier)) !== null && _a !== void 0 ? _a : null;
293 const namedSpecifiers = node.specifiers.filter((specifier) => specifier.type === utils_1.AST_NODE_TYPES.ImportSpecifier);
294 return {
295 defaultSpecifier,
296 namespaceSpecifier,
297 namedSpecifiers,
298 };
299 }
300 /**
301 * Returns information for fixing named specifiers.
302 */
303 function getFixesNamedSpecifiers(fixer, node, typeNamedSpecifiers, allNamedSpecifiers) {
304 if (allNamedSpecifiers.length === 0) {
305 return {
306 typeNamedSpecifiersText: '',
307 removeTypeNamedSpecifiers: [],
308 };
309 }
310 const typeNamedSpecifiersTexts = [];
311 const removeTypeNamedSpecifiers = [];
312 if (typeNamedSpecifiers.length === allNamedSpecifiers.length) {
313 // import Foo, {Type1, Type2} from 'foo'
314 // import DefType, {Type1, Type2} from 'foo'
315 const openingBraceToken = util.nullThrows(sourceCode.getTokenBefore(typeNamedSpecifiers[0], util.isOpeningBraceToken), util.NullThrowsReasons.MissingToken('{', node.type));
316 const commaToken = util.nullThrows(sourceCode.getTokenBefore(openingBraceToken, util.isCommaToken), util.NullThrowsReasons.MissingToken(',', node.type));
317 const closingBraceToken = util.nullThrows(sourceCode.getFirstTokenBetween(openingBraceToken, node.source, util.isClosingBraceToken), util.NullThrowsReasons.MissingToken('}', node.type));
318 // import DefType, {...} from 'foo'
319 // ^^^^^^^ remove
320 removeTypeNamedSpecifiers.push(fixer.removeRange([commaToken.range[0], closingBraceToken.range[1]]));
321 typeNamedSpecifiersTexts.push(sourceCode.text.slice(openingBraceToken.range[1], closingBraceToken.range[0]));
322 }
323 else {
324 const typeNamedSpecifierGroups = [];
325 let group = [];
326 for (const namedSpecifier of allNamedSpecifiers) {
327 if (typeNamedSpecifiers.includes(namedSpecifier)) {
328 group.push(namedSpecifier);
329 }
330 else if (group.length) {
331 typeNamedSpecifierGroups.push(group);
332 group = [];
333 }
334 }
335 if (group.length) {
336 typeNamedSpecifierGroups.push(group);
337 }
338 for (const namedSpecifiers of typeNamedSpecifierGroups) {
339 const { removeRange, textRange } = getNamedSpecifierRanges(namedSpecifiers, allNamedSpecifiers);
340 removeTypeNamedSpecifiers.push(fixer.removeRange(removeRange));
341 typeNamedSpecifiersTexts.push(sourceCode.text.slice(...textRange));
342 }
343 }
344 return {
345 typeNamedSpecifiersText: typeNamedSpecifiersTexts.join(','),
346 removeTypeNamedSpecifiers,
347 };
348 }
349 /**
350 * Returns ranges for fixing named specifier.
351 */
352 function getNamedSpecifierRanges(namedSpecifierGroup, allNamedSpecifiers) {
353 const first = namedSpecifierGroup[0];
354 const last = namedSpecifierGroup[namedSpecifierGroup.length - 1];
355 const removeRange = [first.range[0], last.range[1]];
356 const textRange = [...removeRange];
357 const before = sourceCode.getTokenBefore(first);
358 textRange[0] = before.range[1];
359 if (util.isCommaToken(before)) {
360 removeRange[0] = before.range[0];
361 }
362 else {
363 removeRange[0] = before.range[1];
364 }
365 const isFirst = allNamedSpecifiers[0] === first;
366 const isLast = allNamedSpecifiers[allNamedSpecifiers.length - 1] === last;
367 const after = sourceCode.getTokenAfter(last);
368 textRange[1] = after.range[0];
369 if (isFirst || isLast) {
370 if (util.isCommaToken(after)) {
371 removeRange[1] = after.range[1];
372 }
373 }
374 return {
375 textRange,
376 removeRange,
377 };
378 }
379 /**
380 * insert specifiers to named import node.
381 * e.g.
382 * import type { Already, Type1, Type2 } from 'foo'
383 * ^^^^^^^^^^^^^ insert
384 */
385 function fixInsertNamedSpecifiersInNamedSpecifierList(fixer, target, insertText) {
386 const closingBraceToken = util.nullThrows(sourceCode.getFirstTokenBetween(sourceCode.getFirstToken(target), target.source, util.isClosingBraceToken), util.NullThrowsReasons.MissingToken('}', target.type));
387 const before = sourceCode.getTokenBefore(closingBraceToken);
388 if (!util.isCommaToken(before) && !util.isOpeningBraceToken(before)) {
389 insertText = `,${insertText}`;
390 }
391 return fixer.insertTextBefore(closingBraceToken, `${insertText}`);
392 }
393 function* fixToTypeImportDeclaration(fixer, report, sourceImports) {
394 const { node } = report;
395 const { defaultSpecifier, namespaceSpecifier, namedSpecifiers } = classifySpecifier(node);
396 if (namespaceSpecifier && !defaultSpecifier) {
397 // import * as types from 'foo'
398 yield* fixInsertTypeSpecifierForImportDeclaration(fixer, node, false);
399 return;
400 }
401 else if (defaultSpecifier) {
402 if (report.typeSpecifiers.includes(defaultSpecifier) &&
403 namedSpecifiers.length === 0 &&
404 !namespaceSpecifier) {
405 // import Type from 'foo'
406 yield* fixInsertTypeSpecifierForImportDeclaration(fixer, node, true);
407 return;
408 }
409 }
410 else {
411 if (namedSpecifiers.every(specifier => report.typeSpecifiers.includes(specifier)) &&
412 !namespaceSpecifier) {
413 // import {Type1, Type2} from 'foo'
414 yield* fixInsertTypeSpecifierForImportDeclaration(fixer, node, false);
415 return;
416 }
417 }
418 const typeNamedSpecifiers = namedSpecifiers.filter(specifier => report.typeSpecifiers.includes(specifier));
419 const fixesNamedSpecifiers = getFixesNamedSpecifiers(fixer, node, typeNamedSpecifiers, namedSpecifiers);
420 const afterFixes = [];
421 if (typeNamedSpecifiers.length) {
422 if (sourceImports.typeOnlyNamedImport) {
423 const insertTypeNamedSpecifiers = fixInsertNamedSpecifiersInNamedSpecifierList(fixer, sourceImports.typeOnlyNamedImport, fixesNamedSpecifiers.typeNamedSpecifiersText);
424 if (sourceImports.typeOnlyNamedImport.range[1] <= node.range[0]) {
425 yield insertTypeNamedSpecifiers;
426 }
427 else {
428 afterFixes.push(insertTypeNamedSpecifiers);
429 }
430 }
431 else {
432 yield fixer.insertTextBefore(node, `import type {${fixesNamedSpecifiers.typeNamedSpecifiersText}} from ${sourceCode.getText(node.source)};\n`);
433 }
434 }
435 const fixesRemoveTypeNamespaceSpecifier = [];
436 if (namespaceSpecifier &&
437 report.typeSpecifiers.includes(namespaceSpecifier)) {
438 // import Foo, * as Type from 'foo'
439 // import DefType, * as Type from 'foo'
440 // import DefType, * as Type from 'foo'
441 const commaToken = util.nullThrows(sourceCode.getTokenBefore(namespaceSpecifier, util.isCommaToken), util.NullThrowsReasons.MissingToken(',', node.type));
442 // import Def, * as Ns from 'foo'
443 // ^^^^^^^^^ remove
444 fixesRemoveTypeNamespaceSpecifier.push(fixer.removeRange([commaToken.range[0], namespaceSpecifier.range[1]]));
445 // import type * as Ns from 'foo'
446 // ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ insert
447 yield fixer.insertTextBefore(node, `import type ${sourceCode.getText(namespaceSpecifier)} from ${sourceCode.getText(node.source)};\n`);
448 }
449 if (defaultSpecifier &&
450 report.typeSpecifiers.includes(defaultSpecifier)) {
451 if (report.typeSpecifiers.length === node.specifiers.length) {
452 const importToken = util.nullThrows(sourceCode.getFirstToken(node, isImportToken), util.NullThrowsReasons.MissingToken('import', node.type));
453 // import type Type from 'foo'
454 // ^^^^ insert
455 yield fixer.insertTextAfter(importToken, ' type');
456 }
457 else {
458 const commaToken = util.nullThrows(sourceCode.getTokenAfter(defaultSpecifier, util.isCommaToken), util.NullThrowsReasons.MissingToken(',', defaultSpecifier.type));
459 // import Type , {...} from 'foo'
460 // ^^^^^ pick
461 const defaultText = sourceCode.text
462 .slice(defaultSpecifier.range[0], commaToken.range[0])
463 .trim();
464 yield fixer.insertTextBefore(node, `import type ${defaultText} from ${sourceCode.getText(node.source)};\n`);
465 const afterToken = util.nullThrows(sourceCode.getTokenAfter(commaToken, { includeComments: true }), util.NullThrowsReasons.MissingToken('any token', node.type));
466 // import Type , {...} from 'foo'
467 // ^^^^^^^ remove
468 yield fixer.removeRange([
469 defaultSpecifier.range[0],
470 afterToken.range[0],
471 ]);
472 }
473 }
474 yield* fixesNamedSpecifiers.removeTypeNamedSpecifiers;
475 yield* fixesRemoveTypeNamespaceSpecifier;
476 yield* afterFixes;
477 }
478 function* fixInsertTypeSpecifierForImportDeclaration(fixer, node, isDefaultImport) {
479 // import type Foo from 'foo'
480 // ^^^^^ insert
481 const importToken = util.nullThrows(sourceCode.getFirstToken(node, isImportToken), util.NullThrowsReasons.MissingToken('import', node.type));
482 yield fixer.insertTextAfter(importToken, ' type');
483 if (isDefaultImport) {
484 // Has default import
485 const openingBraceToken = sourceCode.getFirstTokenBetween(importToken, node.source, util.isOpeningBraceToken);
486 if (openingBraceToken) {
487 // Only braces. e.g. import Foo, {} from 'foo'
488 const commaToken = util.nullThrows(sourceCode.getTokenBefore(openingBraceToken, util.isCommaToken), util.NullThrowsReasons.MissingToken(',', node.type));
489 const closingBraceToken = util.nullThrows(sourceCode.getFirstTokenBetween(openingBraceToken, node.source, util.isClosingBraceToken), util.NullThrowsReasons.MissingToken('}', node.type));
490 // import type Foo, {} from 'foo'
491 // ^^ remove
492 yield fixer.removeRange([
493 commaToken.range[0],
494 closingBraceToken.range[1],
495 ]);
496 const specifiersText = sourceCode.text.slice(commaToken.range[1], closingBraceToken.range[1]);
497 if (node.specifiers.length > 1) {
498 // import type Foo from 'foo'
499 // import type {...} from 'foo' // <- insert
500 yield fixer.insertTextAfter(node, `\nimport type${specifiersText} from ${sourceCode.getText(node.source)};`);
501 }
502 }
503 }
504 // make sure we don't do anything like `import type {type T} from 'foo';`
505 for (const specifier of node.specifiers) {
506 if (specifier.type === utils_1.AST_NODE_TYPES.ImportSpecifier &&
507 specifier.importKind === 'type') {
508 yield* fixRemoveTypeSpecifierFromImportSpecifier(fixer, specifier);
509 }
510 }
511 }
512 function* fixToValueImportDeclaration(fixer, report, sourceImports) {
513 const { node } = report;
514 const { defaultSpecifier, namespaceSpecifier, namedSpecifiers } = classifySpecifier(node);
515 if (namespaceSpecifier) {
516 // import type * as types from 'foo'
517 yield* fixRemoveTypeSpecifierFromImportDeclaration(fixer, node);
518 return;
519 }
520 else if (defaultSpecifier) {
521 if (report.valueSpecifiers.includes(defaultSpecifier) &&
522 namedSpecifiers.length === 0) {
523 // import type Type from 'foo'
524 yield* fixRemoveTypeSpecifierFromImportDeclaration(fixer, node);
525 return;
526 }
527 }
528 else {
529 if (namedSpecifiers.every(specifier => report.valueSpecifiers.includes(specifier))) {
530 // import type {Type1, Type2} from 'foo'
531 yield* fixRemoveTypeSpecifierFromImportDeclaration(fixer, node);
532 return;
533 }
534 }
535 const valueNamedSpecifiers = namedSpecifiers.filter(specifier => report.valueSpecifiers.includes(specifier));
536 const fixesNamedSpecifiers = getFixesNamedSpecifiers(fixer, node, valueNamedSpecifiers, namedSpecifiers);
537 const afterFixes = [];
538 if (valueNamedSpecifiers.length) {
539 if (sourceImports.valueOnlyNamedImport) {
540 const insertTypeNamedSpecifiers = fixInsertNamedSpecifiersInNamedSpecifierList(fixer, sourceImports.valueOnlyNamedImport, fixesNamedSpecifiers.typeNamedSpecifiersText);
541 if (sourceImports.valueOnlyNamedImport.range[1] <= node.range[0]) {
542 yield insertTypeNamedSpecifiers;
543 }
544 else {
545 afterFixes.push(insertTypeNamedSpecifiers);
546 }
547 }
548 else {
549 yield fixer.insertTextBefore(node, `import {${fixesNamedSpecifiers.typeNamedSpecifiersText}} from ${sourceCode.getText(node.source)};\n`);
550 }
551 }
552 yield* fixesNamedSpecifiers.removeTypeNamedSpecifiers;
553 yield* afterFixes;
554 }
555 function* fixRemoveTypeSpecifierFromImportDeclaration(fixer, node) {
556 var _a, _b;
557 // import type Foo from 'foo'
558 // ^^^^ remove
559 const importToken = util.nullThrows(sourceCode.getFirstToken(node, isImportToken), util.NullThrowsReasons.MissingToken('import', node.type));
560 const typeToken = util.nullThrows(sourceCode.getFirstTokenBetween(importToken, (_b = (_a = node.specifiers[0]) === null || _a === void 0 ? void 0 : _a.local) !== null && _b !== void 0 ? _b : node.source, isTypeToken), util.NullThrowsReasons.MissingToken('type', node.type));
561 const afterToken = util.nullThrows(sourceCode.getTokenAfter(typeToken, { includeComments: true }), util.NullThrowsReasons.MissingToken('any token', node.type));
562 yield fixer.removeRange([typeToken.range[0], afterToken.range[0]]);
563 }
564 function* fixRemoveTypeSpecifierFromImportSpecifier(fixer, node) {
565 const typeToken = util.nullThrows(sourceCode.getFirstToken(node, isTypeToken), util.NullThrowsReasons.MissingToken('type', node.type));
566 const afterToken = util.nullThrows(sourceCode.getTokenAfter(typeToken, { includeComments: true }), util.NullThrowsReasons.MissingToken('any token', node.type));
567 yield fixer.removeRange([typeToken.range[0], afterToken.range[0]]);
568 }
569 },
570});
571//# sourceMappingURL=consistent-type-imports.js.map
\No newline at end of file