Socket
Socket
Sign inDemoInstall

automutate

Package Overview
Dependencies
Maintainers
1
Versions
20
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

automutate - npm Package Compare versions

Comparing version 0.8.0 to 0.8.1

test/unit/runMutations.test.ts

14

docs/onboarding.md

@@ -10,3 +10,3 @@ # Onboarding

## Optional Preqrequisites
## Optional Prerequisites

@@ -39,3 +39,3 @@ These will make the onboarding process smoother.

Automutation is driven by an instance of the [`AutoMutator` class](../src/autoMutator.ts).
Automutation is driven by the [`runMutations` function](../src/runMutations.ts).
It requires an [`MutationsProvider`](../src/mutationsProvider.ts) to generate suggestions that will be applied to files.

@@ -46,11 +46,9 @@

```javascript
import { AutoMutator } from "automutate";
import { runMutations } from "automutate";
import { SmileyMutationsProvider } from "./smileyMutationsProvider";
export function createMyAutomutator() {
return new AutoMutator({
mutationsProvider: new SmileyMutationsProvider(),
});
}
await runMutations({
mutationsProvider: new SmileyMutationsProvider(),
});
```

@@ -57,0 +55,0 @@

{
"clearMocks": true,
"extensionsToTreatAsEsm": [".ts"],

@@ -3,0 +4,0 @@ "moduleFileExtensions": ["ts", "js"],

import { MutationRunSettings } from "./runMutations";
/**
* Settings to initialize a new AutoMutator.
*/
export declare type AutoMutatorSettings = MutationRunSettings;
/**
* Runs waves of file mutations.

@@ -29,3 +25,3 @@ *

*/
constructor(settings: AutoMutatorSettings);
constructor(settings: MutationRunSettings);
/**

@@ -32,0 +28,0 @@ * Runs waves of file mutations.

@@ -1,2 +0,1 @@

export * from "./autoMutator";
export * from "./fileProviderFactories/cachingFileProviderFactory";

@@ -3,0 +2,0 @@ export * from "./fileProviders/localFileProvider";

@@ -13,3 +13,2 @@ "use strict";

Object.defineProperty(exports, "__esModule", { value: true });
__exportStar(require("./autoMutator"), exports);
__exportStar(require("./fileProviderFactories/cachingFileProviderFactory"), exports);

@@ -16,0 +15,0 @@ __exportStar(require("./fileProviders/localFileProvider"), exports);

@@ -1,11 +0,14 @@

import { MutationsApplier, MutationsApplierSettings } from "../types/mutationsApplier";
import { MutatorFactory } from "../mutatorFactory";
import { Logger } from "../types/logger";
import { FileProviderFactory } from "../types/fileProviderFactory";
import { MutationsApplier } from "../types/mutationsApplier";
import { FileMutations } from "../mutationsProvider";
/**
* Settings to apply individual waves of file mutations to local files.
* Settings to initialize a new FileMutationsApplier.
*/
export interface FileMutationsApplierSettings extends Partial<MutationsApplierSettings> {
export interface FileMutationsApplierSettings {
/**
* Additional directories to search for mutators within.
* Creates file providers for files.
*/
mutatorDirectories?: string[];
fileProviderFactory?: FileProviderFactory;
/**

@@ -15,2 +18,6 @@ * Generates output messages for significant operations.

logger: Logger;
/**
* Creates mutators for mutations.
*/
mutatorFactory?: MutatorFactory;
}

@@ -20,4 +27,16 @@ /**

*/
export declare class FileMutationsApplier extends MutationsApplier {
export declare class FileMutationsApplier implements MutationsApplier {
/**
* Creates file providers for files.
*/
private readonly fileProviderFactory;
/**
* Generates output messages for significant operations.
*/
private readonly logger;
/**
* Creates mutators for mutations.
*/
private readonly mutatorFactory;
/**
* Initializes a new instance of the FileMutationsApplier class.

@@ -28,2 +47,17 @@ *

constructor(settings: FileMutationsApplierSettings);
/**
* Applies an iteration of file mutations.
*
* @param mutations Mutations to be applied to files.
* @returns A Promise for the file mutations being applied.
*/
apply(mutations: FileMutations): Promise<void>;
/**
* Applies a file's mutations.
*
* @param fileName Name of the file.
* @param mutations Mutations to be applied to the file.
* @returns A Promise for the result of the file's mutations.
*/
private applyFileMutations;
}

@@ -25,10 +25,10 @@ "use strict";

const localFileProvider_1 = require("../fileProviders/localFileProvider");
const mutationsApplier_1 = require("../types/mutationsApplier");
const mutatorFactory_1 = require("../mutatorFactory");
const cachingFileProviderFactory_1 = require("../fileProviderFactories/cachingFileProviderFactory");
const commonJSMutatorSearcher_1 = require("../mutatorSearchers/commonJSMutatorSearcher");
const ordering_1 = require("../ordering");
/**
* Applies individual waves of file mutations to local files.
*/
class FileMutationsApplier extends mutationsApplier_1.MutationsApplier {
class FileMutationsApplier {
/**

@@ -40,15 +40,44 @@ * Initializes a new instance of the FileMutationsApplier class.

constructor(settings) {
super({
fileProviderFactory: settings.fileProviderFactory ??
new cachingFileProviderFactory_1.CachingFileProviderFactory((fileName) => new localFileProvider_1.LocalFileProvider(fileName)),
logger: settings.logger,
mutatorFactory: settings.mutatorFactory ??
this.fileProviderFactory =
settings.fileProviderFactory ??
new cachingFileProviderFactory_1.CachingFileProviderFactory((fileName) => new localFileProvider_1.LocalFileProvider(fileName));
this.logger = settings.logger;
this.mutatorFactory =
settings.mutatorFactory ??
new mutatorFactory_1.MutatorFactory(new commonJSMutatorSearcher_1.CommonJSMutatorSearcher([
path.join(__dirname, "../../lib/mutators"),
...(settings.mutatorDirectories || []),
]), settings.logger),
});
]), settings.logger);
}
/**
* Applies an iteration of file mutations.
*
* @param mutations Mutations to be applied to files.
* @returns A Promise for the file mutations being applied.
*/
async apply(mutations) {
await Promise.all(Object.keys(mutations).map(async (fileName) => {
await this.applyFileMutations(fileName, mutations[fileName]);
}));
this.logger.onComplete();
}
/**
* Applies a file's mutations.
*
* @param fileName Name of the file.
* @param mutations Mutations to be applied to the file.
* @returns A Promise for the result of the file's mutations.
*/
async applyFileMutations(fileName, mutations) {
const mutationsOrdered = ordering_1.orderMutationsLastToFirstWithoutOverlaps(mutations);
const fileProvider = this.fileProviderFactory.generate(fileName);
let fileContents = await fileProvider.read();
for (const mutation of mutationsOrdered) {
fileContents = this.mutatorFactory.generateAndApply(fileContents, mutation);
this.logger.onMutation(fileName, mutation);
}
await fileProvider.write(fileContents);
return fileContents;
}
}
exports.FileMutationsApplier = FileMutationsApplier;
//# sourceMappingURL=fileMutationsApplier.js.map

@@ -1,2 +0,1 @@

import { AutoMutatorSettings } from "./autoMutator";
import { Logger } from "./types/logger";

@@ -21,3 +20,17 @@ import { MutationsApplier } from "./types/mutationsApplier";

mutationsProvider: MutationsProvider;
/**
* Settings controlling how many waves to run.
*/
waves?: WavesSettings;
}
export interface WavesSettings {
/**
* Maximum number of waves to run, if not infinite.
*/
maximum?: number;
/**
* Minimum number of waves to run, if not 0.
*/
minimum?: number;
}
/**

@@ -37,2 +50,2 @@ * Reported results from running waves of mutations.

*/
export declare const runMutations: (settings: AutoMutatorSettings) => Promise<MutationRunResults>;
export declare const runMutations: (settings: MutationRunSettings) => Promise<MutationRunResults>;

@@ -12,8 +12,12 @@ "use strict";

exports.runMutations = async (settings) => {
const logger = settings.logger || new consoleLogger_1.ConsoleLogger();
const logger = settings.logger ?? new consoleLogger_1.ConsoleLogger();
const mutatedFileNames = new Set();
const mutationsApplier = settings.mutationsApplier || new fileMutationsApplier_1.FileMutationsApplier({ logger });
while (true) {
const mutationsApplier = settings.mutationsApplier ?? new fileMutationsApplier_1.FileMutationsApplier({ logger });
const { maximum = Infinity, minimum = 0 } = settings.waves ?? {};
for (let i = 0; i < maximum; i += 1) {
const mutationsWave = await settings.mutationsProvider.provide();
if (mutationsWave.fileMutations === undefined) {
if (i < minimum) {
continue;
}
break;

@@ -20,0 +24,0 @@ }

@@ -1,46 +0,7 @@

import { FileProviderFactory } from "./fileProviderFactory";
import { Logger } from "./logger";
import { Mutation } from "./mutation";
import { FileMutations } from "../mutationsProvider";
import { MutatorFactory } from "../mutatorFactory";
/**
* Settings to initialize a new MutationsApplier.
* Applies individual waves of mutations.
*/
export interface MutationsApplierSettings {
export interface MutationsApplier {
/**
* Creates file providers for files.
*/
fileProviderFactory: FileProviderFactory;
/**
* Generates output messages for significant operations.
*/
logger: Logger;
/**
* Creates mutators for mutations.
*/
mutatorFactory: MutatorFactory;
}
/**
* Applies individual waves of file mutations.
*/
export declare class MutationsApplier {
/**
* Creates file providers for files.
*/
private readonly fileProviderFactory;
/**
* Generates output messages for significant operations.
*/
private readonly logger;
/**
* Creates mutators for mutations.
*/
private readonly mutatorFactory;
/**
* Initializes a new instance of the MutationsApplier class.
*
* @param settings Settings to be used for initialization.
*/
constructor(settings: MutationsApplierSettings);
/**
* Applies an iteration of file mutations.

@@ -52,10 +13,2 @@ *

apply(mutations: FileMutations): Promise<void>;
/**
* Applies a file's mutations.
*
* @param fileName Name of the file.
* @param mutations Mutations to be applied to the file.
* @returns A Promise for the result of the file's mutations.
*/
applyFileMutations(fileName: string, mutations: ReadonlyArray<Mutation>): Promise<string>;
}
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.MutationsApplier = void 0;
const ordering_1 = require("../ordering");
/**
* Applies individual waves of file mutations.
*/
class MutationsApplier {
/**
* Initializes a new instance of the MutationsApplier class.
*
* @param settings Settings to be used for initialization.
*/
constructor(settings) {
this.logger = settings.logger;
this.fileProviderFactory = settings.fileProviderFactory;
this.mutatorFactory = settings.mutatorFactory;
}
/**
* Applies an iteration of file mutations.
*
* @param mutations Mutations to be applied to files.
* @returns A Promise for the file mutations being applied.
*/
async apply(mutations) {
await Promise.all(Object.keys(mutations).map(async (fileName) => {
await this.applyFileMutations(fileName, mutations[fileName]);
}));
this.logger.onComplete();
}
/**
* Applies a file's mutations.
*
* @param fileName Name of the file.
* @param mutations Mutations to be applied to the file.
* @returns A Promise for the result of the file's mutations.
*/
async applyFileMutations(fileName, mutations) {
const mutationsOrdered = ordering_1.orderMutationsLastToFirstWithoutOverlaps(mutations);
const fileProvider = this.fileProviderFactory.generate(fileName);
let fileContents = await fileProvider.read();
for (const mutation of mutationsOrdered) {
fileContents = this.mutatorFactory.generateAndApply(fileContents, mutation);
this.logger.onMutation(fileName, mutation);
}
await fileProvider.write(fileContents);
return fileContents;
}
}
exports.MutationsApplier = MutationsApplier;
//# sourceMappingURL=mutationsApplier.js.map
{
"name": "automutate",
"version": "0.8.0",
"version": "0.8.1",
"description": "Applies waves of mutations provided by other tools, such as linters.",

@@ -5,0 +5,0 @@ "main": "lib/index.js",

@@ -8,6 +8,6 @@ # automutate

There are [many](https://github.com/eslint/eslint) [linters](https://github.com/palantir/tslint) [in](https://github.com/stylelint/stylelint) [the](https://github.com/lesshint/lesshint) [world](https://github.com/sasstools/sass-lint) and most are adding or have added ways to `--fix` rule failures automatically.
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 appling to overlapping sets of characters requires logic to handle applying one, then re-running linting, and so on.
- **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).

@@ -81,6 +81,6 @@

# Project Onboarding
## Project Onboarding
See [Onboarding](docs/onboarding.md).
`automutate` requires NodeJS >= 4.
`automutate` requires NodeJS >= 14.

@@ -1,2 +0,1 @@

export * from "./autoMutator";
export * from "./fileProviderFactories/cachingFileProviderFactory";

@@ -3,0 +2,0 @@ export * from "./fileProviders/localFileProvider";

@@ -5,6 +5,2 @@ import * as path from "path";

import { LocalFileProvider } from "../fileProviders/localFileProvider";
import {
MutationsApplier,
MutationsApplierSettings,
} from "../types/mutationsApplier";
import { MutatorFactory } from "../mutatorFactory";

@@ -14,12 +10,16 @@ import { CachingFileProviderFactory } from "../fileProviderFactories/cachingFileProviderFactory";

import { Logger } from "../types/logger";
import { FileProviderFactory } from "../types/fileProviderFactory";
import { MutationsApplier } from "../types/mutationsApplier";
import { FileMutations } from "../mutationsProvider";
import { Mutation } from "../types/mutation";
import { orderMutationsLastToFirstWithoutOverlaps } from "../ordering";
/**
* Settings to apply individual waves of file mutations to local files.
* Settings to initialize a new FileMutationsApplier.
*/
export interface FileMutationsApplierSettings
extends Partial<MutationsApplierSettings> {
export interface FileMutationsApplierSettings {
/**
* Additional directories to search for mutators within.
* Creates file providers for files.
*/
mutatorDirectories?: string[];
fileProviderFactory?: FileProviderFactory;

@@ -30,2 +30,7 @@ /**

logger: Logger;
/**
* Creates mutators for mutations.
*/
mutatorFactory?: MutatorFactory;
}

@@ -36,4 +41,19 @@

*/
export class FileMutationsApplier extends MutationsApplier {
export class FileMutationsApplier implements MutationsApplier {
/**
* Creates file providers for files.
*/
private readonly fileProviderFactory: FileProviderFactory;
/**
* Generates output messages for significant operations.
*/
private readonly logger: Logger;
/**
* Creates mutators for mutations.
*/
private readonly mutatorFactory: MutatorFactory;
/**
* Initializes a new instance of the FileMutationsApplier class.

@@ -44,20 +64,63 @@ *

public constructor(settings: FileMutationsApplierSettings) {
super({
fileProviderFactory:
settings.fileProviderFactory ??
new CachingFileProviderFactory(
(fileName: string): FileProvider => new LocalFileProvider(fileName)
),
logger: settings.logger,
mutatorFactory:
settings.mutatorFactory ??
new MutatorFactory(
new CommonJSMutatorSearcher([
path.join(__dirname, "../../lib/mutators"),
...(settings.mutatorDirectories || []),
]),
settings.logger
),
});
this.fileProviderFactory =
settings.fileProviderFactory ??
new CachingFileProviderFactory(
(fileName: string): FileProvider => new LocalFileProvider(fileName)
);
this.logger = settings.logger;
this.mutatorFactory =
settings.mutatorFactory ??
new MutatorFactory(
new CommonJSMutatorSearcher([
path.join(__dirname, "../../lib/mutators"),
]),
settings.logger
);
}
/**
* Applies an iteration of file mutations.
*
* @param mutations Mutations to be applied to files.
* @returns A Promise for the file mutations being applied.
*/
public async apply(mutations: FileMutations): Promise<void> {
await Promise.all(
Object.keys(mutations).map(async (fileName: string): Promise<void> => {
await this.applyFileMutations(fileName, mutations[fileName]);
})
);
this.logger.onComplete();
}
/**
* Applies a file's mutations.
*
* @param fileName Name of the file.
* @param mutations Mutations to be applied to the file.
* @returns A Promise for the result of the file's mutations.
*/
private async applyFileMutations(
fileName: string,
mutations: ReadonlyArray<Mutation>
) {
const mutationsOrdered: Mutation[] =
orderMutationsLastToFirstWithoutOverlaps(mutations);
const fileProvider: FileProvider =
this.fileProviderFactory.generate(fileName);
let fileContents = await fileProvider.read();
for (const mutation of mutationsOrdered) {
fileContents = this.mutatorFactory.generateAndApply(
fileContents,
mutation
);
this.logger.onMutation(fileName, mutation);
}
await fileProvider.write(fileContents);
return fileContents;
}
}

@@ -1,2 +0,1 @@

import { AutoMutatorSettings } from "./autoMutator";
import { Logger } from "./types/logger";

@@ -6,3 +5,3 @@ import { ConsoleLogger } from "./loggers/consoleLogger";

import { FileMutationsApplier } from "./mutationsAppliers/fileMutationsApplier";
import { MutationsProvider, MutationsWave } from "./mutationsProvider";
import { MutationsProvider } from "./mutationsProvider";

@@ -27,4 +26,21 @@ /**

mutationsProvider: MutationsProvider;
/**
* Settings controlling how many waves to run.
*/
waves?: WavesSettings;
}
export interface WavesSettings {
/**
* Maximum number of waves to run, if not infinite.
*/
maximum?: number;
/**
* Minimum number of waves to run, if not 0.
*/
minimum?: number;
}
/**

@@ -46,13 +62,17 @@ * Reported results from running waves of mutations.

export const runMutations = async (
settings: AutoMutatorSettings
settings: MutationRunSettings
): Promise<MutationRunResults> => {
const logger = settings.logger || new ConsoleLogger();
const logger = settings.logger ?? new ConsoleLogger();
const mutatedFileNames = new Set<string>();
const mutationsApplier =
settings.mutationsApplier || new FileMutationsApplier({ logger });
settings.mutationsApplier ?? new FileMutationsApplier({ logger });
const { maximum = Infinity, minimum = 0 } = settings.waves ?? {};
while (true) {
const mutationsWave: MutationsWave =
await settings.mutationsProvider.provide();
for (let i = 0; i < maximum; i += 1) {
const mutationsWave = await settings.mutationsProvider.provide();
if (mutationsWave.fileMutations === undefined) {
if (i < minimum) {
continue;
}
break;

@@ -59,0 +79,0 @@ }

@@ -1,60 +0,8 @@

import { FileProvider } from "./fileProvider";
import { FileProviderFactory } from "./fileProviderFactory";
import { Logger } from "./logger";
import { Mutation } from "./mutation";
import { FileMutations } from "../mutationsProvider";
import { MutatorFactory } from "../mutatorFactory";
import { orderMutationsLastToFirstWithoutOverlaps } from "../ordering";
/**
* Settings to initialize a new MutationsApplier.
* Applies individual waves of mutations.
*/
export interface MutationsApplierSettings {
export interface MutationsApplier {
/**
* Creates file providers for files.
*/
fileProviderFactory: FileProviderFactory;
/**
* Generates output messages for significant operations.
*/
logger: Logger;
/**
* Creates mutators for mutations.
*/
mutatorFactory: MutatorFactory;
}
/**
* Applies individual waves of file mutations.
*/
export class MutationsApplier {
/**
* Creates file providers for files.
*/
private readonly fileProviderFactory: FileProviderFactory;
/**
* Generates output messages for significant operations.
*/
private readonly logger: Logger;
/**
* Creates mutators for mutations.
*/
private readonly mutatorFactory: MutatorFactory;
/**
* Initializes a new instance of the MutationsApplier class.
*
* @param settings Settings to be used for initialization.
*/
public constructor(settings: MutationsApplierSettings) {
this.logger = settings.logger;
this.fileProviderFactory = settings.fileProviderFactory;
this.mutatorFactory = settings.mutatorFactory;
}
/**
* Applies an iteration of file mutations.

@@ -65,41 +13,3 @@ *

*/
public async apply(mutations: FileMutations): Promise<void> {
await Promise.all(
Object.keys(mutations).map(async (fileName: string): Promise<void> => {
await this.applyFileMutations(fileName, mutations[fileName]);
})
);
this.logger.onComplete();
}
/**
* Applies a file's mutations.
*
* @param fileName Name of the file.
* @param mutations Mutations to be applied to the file.
* @returns A Promise for the result of the file's mutations.
*/
public async applyFileMutations(
fileName: string,
mutations: ReadonlyArray<Mutation>
): Promise<string> {
const mutationsOrdered: Mutation[] =
orderMutationsLastToFirstWithoutOverlaps(mutations);
const fileProvider: FileProvider =
this.fileProviderFactory.generate(fileName);
let fileContents = await fileProvider.read();
for (const mutation of mutationsOrdered) {
fileContents = this.mutatorFactory.generateAndApply(
fileContents,
mutation
);
this.logger.onMutation(fileName, mutation);
}
await fileProvider.write(fileContents);
return fileContents;
}
apply(mutations: FileMutations): Promise<void>;
}

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc