1 | "use strict";
|
2 | var __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 | }));
|
9 | var __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 | });
|
14 | var __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 | };
|
21 | Object.defineProperty(exports, "__esModule", { value: true });
|
22 | const utils_1 = require("@typescript-eslint/utils");
|
23 | const scope_manager_1 = require("@typescript-eslint/scope-manager");
|
24 | const util = __importStar(require("../util"));
|
25 | exports.default = util.createRule({
|
26 | name: 'no-unused-vars',
|
27 | meta: {
|
28 | type: 'problem',
|
29 | docs: {
|
30 | description: 'Disallow unused variables',
|
31 | recommended: 'warn',
|
32 | extendsBaseRule: true,
|
33 | },
|
34 | schema: [
|
35 | {
|
36 | oneOf: [
|
37 | {
|
38 | enum: ['all', 'local'],
|
39 | },
|
40 | {
|
41 | type: 'object',
|
42 | properties: {
|
43 | vars: {
|
44 | enum: ['all', 'local'],
|
45 | },
|
46 | varsIgnorePattern: {
|
47 | type: 'string',
|
48 | },
|
49 | args: {
|
50 | enum: ['all', 'after-used', 'none'],
|
51 | },
|
52 | ignoreRestSiblings: {
|
53 | type: 'boolean',
|
54 | },
|
55 | argsIgnorePattern: {
|
56 | type: 'string',
|
57 | },
|
58 | caughtErrors: {
|
59 | enum: ['all', 'none'],
|
60 | },
|
61 | caughtErrorsIgnorePattern: {
|
62 | type: 'string',
|
63 | },
|
64 | },
|
65 | additionalProperties: false,
|
66 | },
|
67 | ],
|
68 | },
|
69 | ],
|
70 | messages: {
|
71 | unusedVar: "'{{varName}}' is {{action}} but never used{{additional}}.",
|
72 | },
|
73 | },
|
74 | defaultOptions: [{}],
|
75 | create(context) {
|
76 | const filename = context.getFilename();
|
77 | const sourceCode = context.getSourceCode();
|
78 | const MODULE_DECL_CACHE = new Map();
|
79 | const options = (() => {
|
80 | var _a, _b, _c, _d;
|
81 | const options = {
|
82 | vars: 'all',
|
83 | args: 'after-used',
|
84 | ignoreRestSiblings: false,
|
85 | caughtErrors: 'none',
|
86 | };
|
87 | const [firstOption] = context.options;
|
88 | if (firstOption) {
|
89 | if (typeof firstOption === 'string') {
|
90 | options.vars = firstOption;
|
91 | }
|
92 | else {
|
93 | options.vars = (_a = firstOption.vars) !== null && _a !== void 0 ? _a : options.vars;
|
94 | options.args = (_b = firstOption.args) !== null && _b !== void 0 ? _b : options.args;
|
95 | options.ignoreRestSiblings =
|
96 | (_c = firstOption.ignoreRestSiblings) !== null && _c !== void 0 ? _c : options.ignoreRestSiblings;
|
97 | options.caughtErrors =
|
98 | (_d = firstOption.caughtErrors) !== null && _d !== void 0 ? _d : options.caughtErrors;
|
99 | if (firstOption.varsIgnorePattern) {
|
100 | options.varsIgnorePattern = new RegExp(firstOption.varsIgnorePattern, 'u');
|
101 | }
|
102 | if (firstOption.argsIgnorePattern) {
|
103 | options.argsIgnorePattern = new RegExp(firstOption.argsIgnorePattern, 'u');
|
104 | }
|
105 | if (firstOption.caughtErrorsIgnorePattern) {
|
106 | options.caughtErrorsIgnorePattern = new RegExp(firstOption.caughtErrorsIgnorePattern, 'u');
|
107 | }
|
108 | }
|
109 | }
|
110 | return options;
|
111 | })();
|
112 | function collectUnusedVariables() {
|
113 | var _a, _b, _c;
|
114 | |
115 |
|
116 |
|
117 |
|
118 |
|
119 | function hasRestSpreadSibling(variable) {
|
120 | if (options.ignoreRestSiblings) {
|
121 | return variable.defs.some(def => {
|
122 | const propertyNode = def.name.parent;
|
123 | const patternNode = propertyNode.parent;
|
124 | return (propertyNode.type === utils_1.AST_NODE_TYPES.Property &&
|
125 | patternNode.type === utils_1.AST_NODE_TYPES.ObjectPattern &&
|
126 | patternNode.properties[patternNode.properties.length - 1].type ===
|
127 | utils_1.AST_NODE_TYPES.RestElement);
|
128 | });
|
129 | }
|
130 | return false;
|
131 | }
|
132 | |
133 |
|
134 |
|
135 |
|
136 |
|
137 | function isAfterLastUsedArg(variable) {
|
138 | const def = variable.defs[0];
|
139 | const params = context.getDeclaredVariables(def.node);
|
140 | const posteriorParams = params.slice(params.indexOf(variable) + 1);
|
141 |
|
142 | return !posteriorParams.some(v => v.references.length > 0 || v.eslintUsed);
|
143 | }
|
144 | const unusedVariablesOriginal = util.collectUnusedVariables(context);
|
145 | const unusedVariablesReturn = [];
|
146 | for (const variable of unusedVariablesOriginal) {
|
147 |
|
148 | if (variable.defs.length === 0) {
|
149 | unusedVariablesReturn.push(variable);
|
150 | continue;
|
151 | }
|
152 | const def = variable.defs[0];
|
153 | if (variable.scope.type === utils_1.TSESLint.Scope.ScopeType.global &&
|
154 | options.vars === 'local') {
|
155 |
|
156 | continue;
|
157 | }
|
158 |
|
159 | if (def.type === utils_1.TSESLint.Scope.DefinitionType.CatchClause) {
|
160 | if (options.caughtErrors === 'none') {
|
161 | continue;
|
162 | }
|
163 |
|
164 | if ('name' in def.name &&
|
165 | ((_a = options.caughtErrorsIgnorePattern) === null || _a === void 0 ? void 0 : _a.test(def.name.name))) {
|
166 | continue;
|
167 | }
|
168 | }
|
169 | if (def.type === utils_1.TSESLint.Scope.DefinitionType.Parameter) {
|
170 |
|
171 | if (options.args === 'none') {
|
172 | continue;
|
173 | }
|
174 |
|
175 | if ('name' in def.name &&
|
176 | ((_b = options.argsIgnorePattern) === null || _b === void 0 ? void 0 : _b.test(def.name.name))) {
|
177 | continue;
|
178 | }
|
179 |
|
180 | if (options.args === 'after-used' &&
|
181 | util.isFunction(def.name.parent) &&
|
182 | !isAfterLastUsedArg(variable)) {
|
183 | continue;
|
184 | }
|
185 | }
|
186 | else {
|
187 |
|
188 | if ('name' in def.name &&
|
189 | ((_c = options.varsIgnorePattern) === null || _c === void 0 ? void 0 : _c.test(def.name.name))) {
|
190 | continue;
|
191 | }
|
192 | }
|
193 | if (hasRestSpreadSibling(variable)) {
|
194 | continue;
|
195 | }
|
196 |
|
197 |
|
198 | if (variable.eslintUsed) {
|
199 | continue;
|
200 | }
|
201 | unusedVariablesReturn.push(variable);
|
202 | }
|
203 | return unusedVariablesReturn;
|
204 | }
|
205 | return {
|
206 |
|
207 | [ambientDeclarationSelector(utils_1.AST_NODE_TYPES.Program, true)](node) {
|
208 | if (!util.isDefinitionFile(filename)) {
|
209 | return;
|
210 | }
|
211 | markDeclarationChildAsUsed(node);
|
212 | },
|
213 |
|
214 |
|
215 | 'TSModuleDeclaration > TSModuleDeclaration'(node) {
|
216 | if (node.id.type === utils_1.AST_NODE_TYPES.Identifier) {
|
217 | let scope = context.getScope();
|
218 | if (scope.upper) {
|
219 | scope = scope.upper;
|
220 | }
|
221 | const superVar = scope.set.get(node.id.name);
|
222 | if (superVar) {
|
223 | superVar.eslintUsed = true;
|
224 | }
|
225 | }
|
226 | },
|
227 |
|
228 | [ambientDeclarationSelector('TSModuleDeclaration[declare = true] > TSModuleBlock TSModuleDeclaration > TSModuleBlock', false)](node) {
|
229 | markDeclarationChildAsUsed(node);
|
230 | },
|
231 |
|
232 | [ambientDeclarationSelector('TSModuleDeclaration[declare = true] > TSModuleBlock', false)](node) {
|
233 | var _a;
|
234 | const moduleDecl = util.nullThrows((_a = node.parent) === null || _a === void 0 ? void 0 : _a.parent, util.NullThrowsReasons.MissingParent);
|
235 |
|
236 |
|
237 | if (moduleDecl.id.type === utils_1.AST_NODE_TYPES.Literal &&
|
238 | checkModuleDeclForExportEquals(moduleDecl)) {
|
239 | return;
|
240 | }
|
241 | markDeclarationChildAsUsed(node);
|
242 | },
|
243 |
|
244 | 'Program:exit'(programNode) {
|
245 | |
246 |
|
247 |
|
248 |
|
249 |
|
250 |
|
251 | function getDefinedMessageData(unusedVar) {
|
252 | var _a;
|
253 | const defType = (_a = unusedVar === null || unusedVar === void 0 ? void 0 : unusedVar.defs[0]) === null || _a === void 0 ? void 0 : _a.type;
|
254 | let type;
|
255 | let pattern;
|
256 | if (defType === utils_1.TSESLint.Scope.DefinitionType.CatchClause &&
|
257 | options.caughtErrorsIgnorePattern) {
|
258 | type = 'args';
|
259 | pattern = options.caughtErrorsIgnorePattern.toString();
|
260 | }
|
261 | else if (defType === utils_1.TSESLint.Scope.DefinitionType.Parameter &&
|
262 | options.argsIgnorePattern) {
|
263 | type = 'args';
|
264 | pattern = options.argsIgnorePattern.toString();
|
265 | }
|
266 | else if (defType !== utils_1.TSESLint.Scope.DefinitionType.Parameter &&
|
267 | options.varsIgnorePattern) {
|
268 | type = 'vars';
|
269 | pattern = options.varsIgnorePattern.toString();
|
270 | }
|
271 | const additional = type
|
272 | ? `. Allowed unused ${type} must match ${pattern}`
|
273 | : '';
|
274 | return {
|
275 | varName: unusedVar.name,
|
276 | action: 'defined',
|
277 | additional,
|
278 | };
|
279 | }
|
280 | |
281 |
|
282 |
|
283 |
|
284 |
|
285 |
|
286 | function getAssignedMessageData(unusedVar) {
|
287 | const additional = options.varsIgnorePattern
|
288 | ? `. Allowed unused vars must match ${options.varsIgnorePattern.toString()}`
|
289 | : '';
|
290 | return {
|
291 | varName: unusedVar.name,
|
292 | action: 'assigned a value',
|
293 | additional,
|
294 | };
|
295 | }
|
296 | const unusedVars = collectUnusedVariables();
|
297 | for (let i = 0, l = unusedVars.length; i < l; ++i) {
|
298 | const unusedVar = unusedVars[i];
|
299 |
|
300 | if (unusedVar.defs.length > 0) {
|
301 | context.report({
|
302 | node: unusedVar.references.length
|
303 | ? unusedVar.references[unusedVar.references.length - 1]
|
304 | .identifier
|
305 | : unusedVar.identifiers[0],
|
306 | messageId: 'unusedVar',
|
307 | data: unusedVar.references.some(ref => ref.isWrite())
|
308 | ? getAssignedMessageData(unusedVar)
|
309 | : getDefinedMessageData(unusedVar),
|
310 | });
|
311 |
|
312 | }
|
313 | else if ('eslintExplicitGlobalComments' in unusedVar &&
|
314 | unusedVar.eslintExplicitGlobalComments) {
|
315 | const directiveComment = unusedVar.eslintExplicitGlobalComments[0];
|
316 | context.report({
|
317 | node: programNode,
|
318 | loc: util.getNameLocationInGlobalDirectiveComment(sourceCode, directiveComment, unusedVar.name),
|
319 | messageId: 'unusedVar',
|
320 | data: getDefinedMessageData(unusedVar),
|
321 | });
|
322 | }
|
323 | }
|
324 | },
|
325 | };
|
326 | function checkModuleDeclForExportEquals(node) {
|
327 | const cached = MODULE_DECL_CACHE.get(node);
|
328 | if (cached != null) {
|
329 | return cached;
|
330 | }
|
331 | if (node.body && node.body.type === utils_1.AST_NODE_TYPES.TSModuleBlock) {
|
332 | for (const statement of node.body.body) {
|
333 | if (statement.type === utils_1.AST_NODE_TYPES.TSExportAssignment) {
|
334 | MODULE_DECL_CACHE.set(node, true);
|
335 | return true;
|
336 | }
|
337 | }
|
338 | }
|
339 | MODULE_DECL_CACHE.set(node, false);
|
340 | return false;
|
341 | }
|
342 | function ambientDeclarationSelector(parent, childDeclare) {
|
343 | return [
|
344 |
|
345 | `${parent} > :matches(${[
|
346 | utils_1.AST_NODE_TYPES.TSInterfaceDeclaration,
|
347 | utils_1.AST_NODE_TYPES.TSTypeAliasDeclaration,
|
348 | ].join(', ')})`,
|
349 |
|
350 | `${parent} > :matches(${[
|
351 | utils_1.AST_NODE_TYPES.ClassDeclaration,
|
352 | utils_1.AST_NODE_TYPES.TSDeclareFunction,
|
353 | utils_1.AST_NODE_TYPES.TSEnumDeclaration,
|
354 | utils_1.AST_NODE_TYPES.TSModuleDeclaration,
|
355 | utils_1.AST_NODE_TYPES.VariableDeclaration,
|
356 | ].join(', ')})${childDeclare ? '[declare = true]' : ''}`,
|
357 | ].join(', ');
|
358 | }
|
359 | function markDeclarationChildAsUsed(node) {
|
360 | var _a;
|
361 | const identifiers = [];
|
362 | switch (node.type) {
|
363 | case utils_1.AST_NODE_TYPES.TSInterfaceDeclaration:
|
364 | case utils_1.AST_NODE_TYPES.TSTypeAliasDeclaration:
|
365 | case utils_1.AST_NODE_TYPES.ClassDeclaration:
|
366 | case utils_1.AST_NODE_TYPES.FunctionDeclaration:
|
367 | case utils_1.AST_NODE_TYPES.TSDeclareFunction:
|
368 | case utils_1.AST_NODE_TYPES.TSEnumDeclaration:
|
369 | case utils_1.AST_NODE_TYPES.TSModuleDeclaration:
|
370 | if (((_a = node.id) === null || _a === void 0 ? void 0 : _a.type) === utils_1.AST_NODE_TYPES.Identifier) {
|
371 | identifiers.push(node.id);
|
372 | }
|
373 | break;
|
374 | case utils_1.AST_NODE_TYPES.VariableDeclaration:
|
375 | for (const declaration of node.declarations) {
|
376 | visitPattern(declaration, pattern => {
|
377 | identifiers.push(pattern);
|
378 | });
|
379 | }
|
380 | break;
|
381 | }
|
382 | let scope = context.getScope();
|
383 | const shouldUseUpperScope = [
|
384 | utils_1.AST_NODE_TYPES.TSModuleDeclaration,
|
385 | utils_1.AST_NODE_TYPES.TSDeclareFunction,
|
386 | ].includes(node.type);
|
387 | if (scope.variableScope !== scope) {
|
388 | scope = scope.variableScope;
|
389 | }
|
390 | else if (shouldUseUpperScope && scope.upper) {
|
391 | scope = scope.upper;
|
392 | }
|
393 | for (const id of identifiers) {
|
394 | const superVar = scope.set.get(id.name);
|
395 | if (superVar) {
|
396 | superVar.eslintUsed = true;
|
397 | }
|
398 | }
|
399 | }
|
400 | function visitPattern(node, cb) {
|
401 | const visitor = new scope_manager_1.PatternVisitor({}, node, cb);
|
402 | visitor.visit(node);
|
403 | }
|
404 | },
|
405 | });
|
406 |
|
407 |
|
408 |
|
409 |
|
410 |
|
411 |
|
412 |
|
413 |
|
414 |
|
415 |
|
416 |
|
417 |
|
418 |
|
419 |
|
420 |
|
421 |
|
422 |
|
423 |
|
424 |
|
425 |
|
426 |
|
427 |
|
428 |
|
429 |
|
430 |
|
431 |
|
432 |
|
433 |
|
434 |
|
435 |
|
436 |
|
437 |
|
438 |
|
439 |
|
440 |
|
441 |
|
442 |
|
443 |
|
444 |
|
445 |
|
446 |
|
447 |
|
448 |
|
449 |
|
450 |
|
451 |
|
452 |
|
453 |
|
454 |
|
455 |
|
456 |
|
457 |
|
458 |
|
459 |
|
460 |
|
461 |
|
462 |
|
463 |
|
464 |
|
465 |
|
466 |
|
467 |
|
468 |
|
469 |
|
470 |
|
471 |
|
472 |
|
473 |
|
474 |
|
475 |
|
476 |
|
477 |
|
478 |
|
479 |
|
480 |
|
481 |
|
482 |
|
483 |
|
484 |
|
485 |
|
486 |
|
487 |
|
488 |
|
489 |
|
490 |
|
491 |
|
492 |
|
493 |
|
494 |
|
495 |
|
496 |
|
497 |
|
498 |
|
499 |
|
500 |
|
501 |
|
\ | No newline at end of file |