Skip to content

Commit

Permalink
Suggest autofixes for declaration diagnostics (#30)
Browse files Browse the repository at this point in the history
Co-authored-by: MichaelMitchell-at <=>
Co-authored-by: Jake Bailey <[email protected]>
  • Loading branch information
MichaelMitchell-at and jakebailey authored May 6, 2024
1 parent 5e18d27 commit 50e122e
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 23 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ Options:
```

`-t path/to/tsconfig.json` or `--tsconfig path/to/tsconfig.json`
Specifies the project to use the tool on. If no arguement given, the tool will use the tsconfig in the current working directory.
Specifies the project to use the tool on. If no argument given, the tool will use the tsconfig in the current working directory.

`-e <number>` or `--errorCode <number>`
Specifies the errors to fix. Several error codes can be specified during the same command.
Expand Down
26 changes: 15 additions & 11 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -112,16 +112,16 @@ export const checkOptions = async (opt: Options): Promise<[string[], string[]]>

// Check git status if the write flag was provided and the output folder is the same as the project folder
// Do not allow overwriting files with previous changes on them unless --ignoreGitStatus flag was provided
if (opt.write && path.dirname(opt.tsconfig) === opt.outputFolder) {
if (!opt.ignoreGitStatus && opt.write && path.dirname(opt.tsconfig) === opt.outputFolder) {
let isModified = false;
const status = await (getGitStatus(opt.tsconfig));
const splitStatus = status.split(/\r?\n/);
if (splitStatus.length && splitStatus[0] != '') {
const re = /[MARCD?]\s(package).+?(json)/g
isModified = splitStatus.length && splitStatus[0] !== '' ? !(splitStatus.filter((text) => { return text.match(re) }).length === splitStatus.length) : false;
}
if (isModified && !opt.ignoreGitStatus) {
throw new Error(`Please provide the --ignoreGitStatus flag if you are sure you'ld like to override your exisiting changes`);
if (isModified) {
throw new Error(`Please provide the --ignoreGitStatus flag if you are sure you'd like to override your existing changes`);
}
}

Expand Down Expand Up @@ -312,12 +312,12 @@ export async function getCodeFixesFromProject(project: Project, opt: Options, ho
return fixesAndDiagnostics;
});

const flatCodeFixesAndDiagnostics = <FixAndDiagnostic[]>_.flatten(codefixesPerFile);
const flatCodeFixesAndDiagnostics: FixAndDiagnostic[] = _.flatten(codefixesPerFile);
let [filteredCodeFixesAndDiagnostics, filteredCodeFixByNameOut] = filterCodeFixesByFixName(flatCodeFixesAndDiagnostics, opt.fixName);
filteredCodeFixByNameOut.forEach((s: string) => { host.log(s); });
[fixesAndDiagnostics, noAppliedFixes] = getAppliedAndNoAppliedFixes(filteredCodeFixesAndDiagnostics);
if (!opt.showMultiple) {
fixesAndDiagnostics = removeMutilpleDiagnostics(fixesAndDiagnostics);
fixesAndDiagnostics = removeMultipleDiagnostics(fixesAndDiagnostics);
}
fixesAndDiagnostics = removeDuplicatedFixes(fixesAndDiagnostics);
if (filteredCodeFixesAndDiagnostics.length) {
Expand All @@ -339,8 +339,12 @@ export async function getCodeFixesFromProject(project: Project, opt: Options, ho
}

export function getDiagnostics(project: Project): (readonly Diagnostic[])[] {
const compilerOptions = project.program.getCompilerOptions();
const diagnostics = project.program.getSourceFiles().map(function (file: SourceFile) {
return project.program.getSemanticDiagnostics(file);
return [
...(compilerOptions.declaration || compilerOptions.composite ? project.program.getDeclarationDiagnostics(file) : []),
...project.program.getSemanticDiagnostics(file),
];
});
return diagnostics;
}
Expand All @@ -350,7 +354,7 @@ export function filterDiagnosticsByFileAndErrorCode(diagnostics: (readonly Diagn
// if errorCodes were passed in, only use the specified errors
// diagnostics is guaranteed to not be [] or [[]]
let filteredDiagnostics = diagnostics.filter((diagnostics) => diagnostics.length);
let returnStrings = <string[]>[];
let returnStrings: string[] = [];

// Check if file is in node_modules, if so remove it from filteredDiagnostics, we'll not be applying fixes there
filteredDiagnostics = filteredDiagnostics.filter((filteredDiagnostic) => {
Expand Down Expand Up @@ -486,7 +490,7 @@ export function filterCodeFixesByFixName(codeFixesAndDiagnostics: FixAndDiagnost
// do we want to distinguish the case when no codefixes are picked? (no hits)

let fixCounter = new Map<string, number>();
let out = <string[]>[];
let out: string[] = [];
const filteredFixesAndDiagnostics = codeFixesAndDiagnostics.filter((codeFixAndDiagnostic) => {
if (codeFixAndDiagnostic.fix && fixNames.includes(codeFixAndDiagnostic.fix.fixName)) {
const currentVal = fixCounter.get(codeFixAndDiagnostic.fix.fixName);
Expand Down Expand Up @@ -532,15 +536,15 @@ async function getUpdatedCodeFixesAndDiagnostics(codeFixesAndDiagnostics: FixAnd
if (userInput === Choices.ACCEPT) {
addToCodefixes(codefixes, [currentCodeFix]);
if (showMultiple) {
codeFixesAndDiagnostics = removeMutilpleDiagnostics(codeFixesAndDiagnostics, Choices.ACCEPT)
codeFixesAndDiagnostics = removeMultipleDiagnostics(codeFixesAndDiagnostics, Choices.ACCEPT)
}
else {
codeFixesAndDiagnostics.splice(0, count);
};
}
else if (userInput === Choices.ACCEPTALL) {
if (showMultiple) {
codeFixesAndDiagnostics = removeMutilpleDiagnostics(codeFixesAndDiagnostics);
codeFixesAndDiagnostics = removeMultipleDiagnostics(codeFixesAndDiagnostics);
}
let updatedFixesAndDiagnostics = codeFixesAndDiagnostics.filter((diagnosticAndFix) => diagnosticAndFix.diagnostic.code === currentDiagnostic.code);
updatedFixesAndDiagnostics.map((diagnosticAndFix) => {
Expand Down Expand Up @@ -632,7 +636,7 @@ export interface ChangeDiagnostic {

// Removes duplicate diagnostics if showMultiple = false
// Also removes multiple code fixes for the diagnostic if the user accepts the first one or to accept all of that type
export function removeMutilpleDiagnostics(codeFixesAndDiagnostics: FixAndDiagnostic[], choice?: Choices.ACCEPT): FixAndDiagnostic[] {
export function removeMultipleDiagnostics(codeFixesAndDiagnostics: FixAndDiagnostic[], choice?: Choices.ACCEPT): FixAndDiagnostic[] {
if (choice === Choices.ACCEPT) {
for (let i = 1; i < codeFixesAndDiagnostics.length; i++) {
let count = 1;
Expand Down
22 changes: 11 additions & 11 deletions test/unit/removeMultipleDiagnostics.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { CodeFixAction, DiagnosticCategory } from "typescript";
import { Choices, FixAndDiagnostic, removeMutilpleDiagnostics } from "../../src";
import { Choices, FixAndDiagnostic, removeMultipleDiagnostics } from "../../src";

//This test is probably not be too effective since splice is being used
function makeCodeFix(fixName: string, start: number, length: number): CodeFixAction {
Expand Down Expand Up @@ -36,7 +36,7 @@ test("removeDuplicatedFixes_twoEqualDiagnostics", () => {
codefixes.forEach((codefix) => {
fixesAndDiagnostics.push(makeFixAndDiagnostic(codefix, 435, 4, 5));
})
const result = removeMutilpleDiagnostics(fixesAndDiagnostics);
const result = removeMultipleDiagnostics(fixesAndDiagnostics);
expect(result).toEqual([fixesAndDiagnostics[0]]);
});

Expand All @@ -46,7 +46,7 @@ test("removeDuplicatedFixes_threeEqualDiagnostics", () => {
codefixes.forEach((codefix) => {
fixesAndDiagnostics.push(makeFixAndDiagnostic(codefix, 435, 4, 5));
})
const result = removeMutilpleDiagnostics(fixesAndDiagnostics);
const result = removeMultipleDiagnostics(fixesAndDiagnostics);
expect(result).toEqual([fixesAndDiagnostics[0]]);
});

Expand All @@ -57,7 +57,7 @@ test("removeDuplicatedFixes_manyEqualDiagnostics", () => {
fixesAndDiagnostics.push(makeFixAndDiagnostic(makeCodeFix('fixOverrideModifier', 165, 0), 435, 4, 5));
i++;
}
const result = removeMutilpleDiagnostics(fixesAndDiagnostics);
const result = removeMultipleDiagnostics(fixesAndDiagnostics);
expect(result).toEqual([fixesAndDiagnostics[0]]);
});

Expand All @@ -70,7 +70,7 @@ test("removeDuplicatedFixes_allDifferentDiagnostics", () => {
fixesAndDiagnostics.push(makeFixAndDiagnostic(codefixes[2], 4333, 5, 64));
fixesAndDiagnostics.push(makeFixAndDiagnostic(codefixes[3], 764, 7, 64));
fixesAndDiagnostics.push(makeFixAndDiagnostic(codefixes[4], 422, 2, 544));
const result = removeMutilpleDiagnostics(fixesAndDiagnostics);
const result = removeMultipleDiagnostics(fixesAndDiagnostics);
expect(result).toEqual(fixesAndDiagnostics);
});

Expand All @@ -79,7 +79,7 @@ test("removeDuplicatedFixes_twoEqualDiagnosticsAndOneDifferent", () => {
fixesAndDiagnostics.push(makeFixAndDiagnostic(makeCodeFix('fixOverrideModifier', 165, 0), 435, 4, 5));
fixesAndDiagnostics.push(makeFixAndDiagnostic(makeCodeFix('addConvertToUnknownForNonOverlappingTypes', 8, 9), 543, 4, 5));
fixesAndDiagnostics.push(makeFixAndDiagnostic(makeCodeFix('fixOverrideModifier', 165, 0), 435, 4, 5));
const result = removeMutilpleDiagnostics(fixesAndDiagnostics);
const result = removeMultipleDiagnostics(fixesAndDiagnostics);
expect(result).toEqual(fixesAndDiagnostics);
});

Expand All @@ -95,14 +95,14 @@ test("removeDuplicatedFixes_someDifferentAndSomeDuplicatedDiagnostics", () => {
fixesAndDiagnostics.push(makeFixAndDiagnostic(makeCodeFix('fixOverrideModifier', 165, 0), 435, 4, 5));
fixesAndDiagnostics.push(makeFixAndDiagnostic(makeCodeFix('addConvertToUnknownForNonOverlappingTypes', 40, 73), 765, 44, 5));
fixesAndDiagnostics.push(makeFixAndDiagnostic(makeCodeFix('fixOverrideModifier', 165, 0), 435, 4, 5));
const result = removeMutilpleDiagnostics(fixesAndDiagnostics);
const result = removeMultipleDiagnostics(fixesAndDiagnostics);
expect(result).toEqual(fixesAndDiagnostics);
});

test("removeDuplicatedFixes_acceptOneOutofOne", () => {
const fixesAndDiagnostics: FixAndDiagnostic[] = [];
fixesAndDiagnostics.push(makeFixAndDiagnostic(makeCodeFix('fixOverrideModifier', 165, 0), 435, 4, 5));
const result = removeMutilpleDiagnostics(fixesAndDiagnostics, Choices.ACCEPT);
const result = removeMultipleDiagnostics(fixesAndDiagnostics, Choices.ACCEPT);
expect(result).toEqual(fixesAndDiagnostics);
});

Expand All @@ -119,7 +119,7 @@ test("removeDuplicatedFixes_acceptAllTheSameCode", () => {
fixesAndDiagnostics.push(makeFixAndDiagnostic(makeCodeFix('fixOverrideModifier', 165, 0), 435, 4, 5));
fixesAndDiagnostics.push(makeFixAndDiagnostic(makeCodeFix('addConvertToUnknownForNonOverlappingTypes', 40, 73), 435, 44, 5));
fixesAndDiagnostics.push(makeFixAndDiagnostic(makeCodeFix('fixOverrideModifier', 165, 0), 435, 4, 5));
const result = removeMutilpleDiagnostics(fixesAndDiagnostics, Choices.ACCEPT);
const result = removeMultipleDiagnostics(fixesAndDiagnostics, Choices.ACCEPT);
expect(result).toEqual(fixesAndDiagnostics);
});

Expand All @@ -133,6 +133,6 @@ test("removeDuplicatedFixes_allTheSameCode", () => {
fixesAndDiagnostics.push(makeFixAndDiagnostic(codefixes[2], 545, 4, 5));
fixesAndDiagnostics.push(makeFixAndDiagnostic(codefixes[3], 435, 6, 5));
fixesAndDiagnostics.push(makeFixAndDiagnostic(codefixes[4], 212, 4, 5));
const result = removeMutilpleDiagnostics(fixesAndDiagnostics, Choices.ACCEPT);
const result = removeMultipleDiagnostics(fixesAndDiagnostics, Choices.ACCEPT);
expect(result).toEqual(fixesAndDiagnostics);
});
});

0 comments on commit 50e122e

Please sign in to comment.