This creates a new "list" output format that includes a certain number
of git SHAs per token. This allows for perusal of the most recent
changes for a given token to understand what changed.
Why?
====
In cases where no matchers are present, a language config should not
auto-classify every match as low-likelihood; instead, it should return
False so subsequent checks can operate on the match itself.
This is related to 9bf9499e67f52bcde2420bfe3945f73cfdaa06d7; both are
handling cases where less configuration data than ideal is present and
the program still needs to operate correctly.
Why?
====
Dynamic languages, and Rails in particular, support some fun method
creation. One common pattern is, within RSpec, to create matchers
dynamically based on predicate methods. Two common examples are:
* `#admin?` gets converted to the matcher `#be_admin`
* `#has_active_todos?` gets converted to the matcher `#have_active_todos`
This especially comes into play when writing page objects with predicate
methods.
This change introduces the concept of aliases, a way to describe the
before/after for these transformations. This introduces a direct swap
with a wildcard value (%s), although this may change in the future to
support other transformations for pluralization, camel-casing, etc.
Externally, aliases are not grouped together by term; however, the
underlying counts are summed together, increasing the total occurrences
and likely pushing the individual method out of "high" likelihood into
"medium" or "low" likelihood.
Closes#19.
Why?
====
This ensures no method/function bleed between languages, which may cause
confusing miscalculation when methods/functions are reused across
different types of projects (e.g. index from Rails migrations and index
action from Phoenix controllers).
Why?
====
Parsec is overkill when all that's really needed is splitting on
semicolons and converting a string to a non-negative Int.
One side-effect of this is to convert the caching mechanism from flat
text to CSV, with cassava handling (de-)serialization.
Additional
==========
Introduce ReaderT to calculate sha once per cache interaction
Previously, we were calculating the fingerprint (SHA) for match results
potentially twice, once when reading from the cache, and a second time
if no cache was found. This introduces a ReaderT to manage cache
interaction with a single fingerprint calculation.
This also abstracts what's being cached to only care about the fact that
the data can be converted to/from csv.
Why?
====
Because a .gitignore file captures a fair number of project-specific
directories and files to ignore, we can use this list to reduce the
number of files to look at when determining a fingerprint for a project.
Because the fingerprint should be based on files we care about changing,
the project-specific .gitignore is a great place to start.
This drastically reduces fingerprint timing - for larger projects, or
projects with a massive number of files (e.g. anything doing anything
significant with NPM and a front-end framework), this will help make
caching usable. For normal projects, this cuts fingerprint
calculation to 10%-20% of what it was previously.
Closes#38
Why?
====
Handling low likelihood configuration was previously a huge pain,
because the syntax in Haskell was fairly terse. This introduces a yaml
format internally that ships with the app covering basic cases for
Rails, Phoenix, and Haskell. I could imagine getting baselines in here
for other languages and frameworks (especially ones I've used and am
comfortable with) as a baseline.
This also paves the way for searching for user-provided additions and
loading those configurations in addition to what we have here.
Why?
====
This library converts lots of strings to positive integers
(specifically, when it's parsing output from search results). Because
these are always positive integers, we can make more assumptions about
the data and how to parse the values.
Corresponding benchmark: https://gist.github.com/joshuaclayton/767c507edf09215d08cdd79c93a5f383
Why?
====
ag supports using regular expressions for searches; however, the -Q
flag, which was previously always used, resulted in literal search
results.
By searching literal matches, it would potentially return too many
results. For example, with a `me` method in a controller, it'd match
words like `awesome` or `method`.
This introduces a check where, if the token being searched is only
composed of word characters (`[A-Za-z0-9_]`), it'll switch over to use
regular expressions with ag and surround the token with non-word matches
on either end. The goal here is to reduce false-positives in matches.
Why?
====
Grouping results can be helpful to view information differently, e.g. to
see highest-offending files or to remove grouping entirely.
This introduces a flag to allow overriding the default group (two levels
of directory)
Why?
====
Parsing lines of results was somewhat unreliable, and terms with odd
characters were causing problems. This:
* extracts parsing into an Unused.Parser.Internal module for ease of
testing
* fixes cases where certain tokens weren't matching
Why?
====
A simple calculation ("yes, this should be removed" or "no, this is
probably fine") is frankly not enough information for someone evaluating
their codebase to understand why we made the decision.
This introduces a removal reason, so a user understands why we ranked it
the way we did, and adds additional logic around a method and its tests
to determine if a method exists and is only being used in the tests (if
so, it should probably be deleted).
This is done with an Occurrances record, which is created for total
files, test code, and non-test code. The test code logic is somewhat
naive but works in most cases. It doesn't ensure a particular directory,
in the case that tests live alongside source code (e.g. Go), and
captures RSpec cases as well.