From fbd4eaef758c471176feb8d3378a342dd4ea8911 Mon Sep 17 00:00:00 2001 From: Zach Millman Date: Fri, 20 Apr 2018 15:37:41 -0700 Subject: [PATCH] Add support for unused_exceptions https://github.com/za-creature/coffeescope/issues/11 --- coffeelint.json | 3 ++- src/Scope.coffee | 6 +++++- src/index.coffee | 32 ++++++++++++++++++++++++++++++-- test/ScopeLinter/unused.coffee | 27 +++++++++++++++++++++++++++ 4 files changed, 64 insertions(+), 4 deletions(-) diff --git a/coffeelint.json b/coffeelint.json index 922c747..7bbfca8 100644 --- a/coffeelint.json +++ b/coffeelint.json @@ -128,7 +128,8 @@ "hoist_local": false, "hoist_parent": true, "unused_variables": true, - "unused_arguments": false + "unused_arguments": false, + "unused_exceptions": ["_.+"] }, "prefer_double_quotes": { "module": "coffeelint-prefer-double-quotes", diff --git a/src/Scope.coffee b/src/Scope.coffee index d35bad2..010f82a 100644 --- a/src/Scope.coffee +++ b/src/Scope.coffee @@ -141,10 +141,14 @@ module.exports = class Scope @options["unused_variables"]) or \ type is "Class" and @options["unused_classes"] or \ type is "Argument" and @options["unused_arguments"] - then do -> + then do => if reads.length or innerReads.length return # variable was read at least once + for exception in @options["unused_exceptions"] or [] + if (new RegExp("^#{exception}$")).test(name) + return # variable is allowed to be unused + for {locationData}, index in writes.concat(innerWrites) # issue a variable-is-assigned-but-never-read warning every # time it is accessed (here and in all child scopes) diff --git a/src/index.coffee b/src/index.coffee index a236956..3bd3a09 100644 --- a/src/index.coffee +++ b/src/index.coffee @@ -117,7 +117,7 @@ module.exports = class Coffeescope2
shadow_exceptions
A list of regular expressions that further customizes the behavior of shadow by allowing one or more - names to be extempt from shadowing warnings. The default + names to be exempt from shadowing warnings. The default value is ["err", "next"] to allow nesting of Node.JS-style continuations. To be skipped, the name must match the entire expression: @@ -184,6 +184,33 @@ module.exports = class Coffeescope2 this warning. Defaults to true because of historical reasons and the low rate of false positives generated on most codebases.
+ +
unused_exceptions
+
A list of regular expressions that further customizes the + behavior of unused_ by allowing one or more + names to be exempt from unused warnings. The default value + is ["_.+"] to skip names starting with + underscores. To be skipped, the name must match the entire + expression: + +
""" level: "warn" @@ -198,7 +225,7 @@ module.exports = class Coffeescope2 shadow: true # warn when overwriting a variable from outer scope shadow_builtins: false # don't warn when "assigning to" a superglobal - shadow_exceptions: ["err", "next"] # list of args that may be shadowed + shadow_exceptions: ["err", "next"] # list of args that may be shadowed undefined: true # warn when accessing an undefined variable hoist_local: true # allow same-scope hoisting @@ -207,6 +234,7 @@ module.exports = class Coffeescope2 unused_variables: true # warn when a variable is not accessed unused_arguments: false # warn when an argument is not accessed unused_classes: true # warn when a class is not instantiated or copied + unused_exceptions: ["_.+"] # list of names that can be unused lintAST: (root, {config, createError}) -> for spec in ScopeLinter.default().lint(root, config[@rule.name]) diff --git a/test/ScopeLinter/unused.coffee b/test/ScopeLinter/unused.coffee index a2dd8fc..6908a88 100644 --- a/test/ScopeLinter/unused.coffee +++ b/test/ScopeLinter/unused.coffee @@ -424,3 +424,30 @@ describe "ScopeLinter/unused", -> unused_variables: true unused_classes: true }).should.have.length(0) + + it "allows exceptions when instructed", -> + ScopeLinter.default().lint(nodes( + """ + _foo = "bar" + class _UnusedKlass + method: (_arg) -> + """ + ), { + unused_variables: true + unused_arguments: true + unused_classes: true + unused_exceptions: ["_.+"] + }).should.have.length(0) + + ScopeLinter.default().lint(nodes( + """ + _foo = "bar" + class _UnusedKlass + method: (_arg) -> + """ + ), { + unused_variables: true + unused_arguments: true + unused_classes: true + unused_exceptions: ["_..."] + }).should.have.length(1) # only catches the unused class