https://github.com/automutate/automutate
Applies waves of mutations provided by other tools, such as linters or codemods.
https://github.com/automutate/automutate
linter mutators static-analysis
Last synced: 10 months ago
JSON representation
Applies waves of mutations provided by other tools, such as linters or codemods.
- Host: GitHub
- URL: https://github.com/automutate/automutate
- Owner: automutate
- License: mit
- Created: 2016-11-08T07:31:24.000Z (over 9 years ago)
- Default Branch: main
- Last Pushed: 2022-07-25T14:33:43.000Z (almost 4 years ago)
- Last Synced: 2025-08-17T01:52:57.941Z (10 months ago)
- Topics: linter, mutators, static-analysis
- Language: TypeScript
- Homepage:
- Size: 312 KB
- Stars: 16
- Watchers: 1
- Forks: 0
- Open Issues: 10
-
Metadata Files:
- Readme: README.md
- License: LICENSE.txt
Awesome Lists containing this project
README
# automutate
[](https://travis-ci.org/automutate/automutate)
[](https://www.npmjs.com/package/automutate)
Applies waves of mutations provided by other tools, such as linters or codemods.
There are [many](https://github.com/eslint/eslint) [linters](https://github.com/stylelint/stylelint) [out](https://github.com/lesshint/lesshint) [there](https://github.com/sasstools/sass-lint) and most include ways to `--fix` rule failures automatically.
This is great but hard to do for a couple of reasons:
- **Overlapping mutations** - The possibility of mutations applying to overlapping sets of characters requires logic to handle applying one, then re-running linting, and so on.
- **Code bloat verses duplication** - Most linters either provide hooks to apply fixes themselves (which can result in code bloat) or have an external project (which duplicates logic for finding rules).
`automutate` proposes that linters only propose **how** to fix rules, via a standardized JSON format.
Having a standardized source-agnostic project to apply mutations brings a couple of benefits:
- **Reduced overhead** - Projects no longer need to do this work themselves.
- **Standardized base** - Ramp-up time to switch between projects using `automutate` is reduced with common code.
In general, _detecting_ rule failures is a separate concern from _fixing_ them.
Linters need to run quickly over a read-only set of files, often during built processes, while fixers typically run slowly and modify files on user request.
## How it works
The main `automutate` algorithm is started in [`autoMutator.ts`](../src/autoMutator.ts) and mostly applied in [`mutationsApplier.ts`](../src/mutationsApplier.ts):
```swift
while mutationsWave = getMutationsWave():
for (file, fileMutations) of groupMutationsByFile(mutationsWave):
for mutation of getNonOverlappingMutationsInReverse(fileMutations):
applyMutation(file, mutation)
```
1. `getMutationsWave` calls to an external tool, such as a linter, to receive a wave of suggested mutations.
2. `groupMutationsByFile` organizes the suggested mutations by file.
3. `getNonOverlappingMutationsInReverse` removes overlapping mutations that would conflict with each other, and sorts the remainder in reverse order so that later mutations don't interfere with character positions of earlier mutations.
4. `applyMutation` modifies files on disk using the remaining mutations.
## Mutations
A single mutation contains a unique `type` identifier, a range of character position(s) to apply to, and optionally other logic.
The following basic text manipulations are provided out of the box:
- **`multiple`** - Container for multiple mutations. This indicates to `automutate` that these must be applied all at once or not at all, which guarantees consistency with the built-in mutation overlap detection.
- **`text-delete`** - Deletes a range of characters.
- **`text-insert`** - Inserts a string at a point.
- **`text-replace`** - Replaces characters matching a string or regular expression within a range.
- **`text-swap`** - Swaps a range of characters with a new string.
For example:
```json
{
"ugly-file.txt": [
{
"range": {
"begin": 7,
"end": 14
},
"type": "text-delete"
},
{
"insertion": "inconceivable!",
"range": {
"begin": 21
},
"type": "text-insert"
}
]
}
```
Linter-specific utilities may define their own mutations.
For example, a language's linter may define a `node-rename` mutation rather than use a `multiple` mutation containing `text-swap` mutations.
See [Mutators](docs/mutators.md) for more on custom mutators.
## Project Onboarding
See [Onboarding](docs/onboarding.md).
`automutate` requires NodeJS >= 14.