Skip to content
This repository has been archived by the owner on Mar 25, 2021. It is now read-only.

Commit

Permalink
fix(Linter): apply fix to the correct file (#2421)
Browse files Browse the repository at this point in the history
Fix #2392

The spec that I added extends the `Linter` in order to test the extra
method I added. Since tslint doesn't have any rules which apply fixes in
a file different from the one which is currently being linted, I didn't
come up with additional tests.
  • Loading branch information
mgechev authored and nchen63 committed Apr 3, 2017
1 parent 5c6cc42 commit 103dc03
Show file tree
Hide file tree
Showing 2 changed files with 100 additions and 10 deletions.
44 changes: 34 additions & 10 deletions src/linter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,16 +104,8 @@ class Linter {
if (this.options.fix) {
for (const rule of enabledRules) {
const ruleFailures = this.applyRule(rule, sourceFile);
const fixes = ruleFailures.map((f) => f.getFix()).filter((f): f is Fix => !!f) as Fix[];
source = fs.readFileSync(fileName, { encoding: "utf-8" });
if (fixes.length > 0) {
this.fixes = this.fixes.concat(ruleFailures);
source = Replacement.applyFixes(source, fixes);
fs.writeFileSync(fileName, source, { encoding: "utf-8" });

// reload AST if file is modified
sourceFile = this.getSourceFile(fileName, source);
}
source = this.applyFixes(fileName, source, ruleFailures);
sourceFile = this.getSourceFile(fileName, source);
fileFailures = fileFailures.concat(ruleFailures);
}
hasLinterRun = true;
Expand Down Expand Up @@ -169,6 +161,38 @@ class Linter {
};
}

// Applies fixes to the files where the failures are reported.
// Returns the content of the source file which AST needs to be reloaded.
protected applyFixes(sourceFilePath: string, sourceContent: string, ruleFailures: RuleFailure[]) {
const fixesPerFile: {[file: string]: Fix[]} = ruleFailures
.reduce((accum: {[file: string]: Fix[]}, c) => {
const currentFileName = c.getFileName();
const fix = c.getFix();
if (fix) {
accum[currentFileName] = accum[currentFileName] || [];
accum[currentFileName].push(fix);
}
return accum;
}, {});

const hasFixes = Object.keys(fixesPerFile).length > 0;
let result = sourceContent;

if (hasFixes) {
this.fixes = this.fixes.concat(ruleFailures);
Object.keys(fixesPerFile).forEach((currentFileName: string) => {
const fixesForFile = fixesPerFile[currentFileName];
let source = fs.readFileSync(currentFileName, { encoding: "utf-8" });
source = Replacement.applyFixes(source, fixesForFile);
fs.writeFileSync(currentFileName, source, { encoding: "utf-8" });
if (sourceFilePath === currentFileName) {
result = source;
}
});
}
return result;
}

private applyRule(rule: IRule, sourceFile: ts.SourceFile) {
let ruleFailures: RuleFailure[] = [];
try {
Expand Down
66 changes: 66 additions & 0 deletions test/linterTests.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/**
* @license
* Copyright 2017 Palantir Technologies, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import * as fs from "fs";
import { createSourceFile, ScriptTarget } from "typescript";
import { Replacement, RuleFailure } from "../src/language/rule/rule";
import { createTempFile } from "./utils";

import Linter = require("../src/linter");

class TestLinter extends Linter {
public applyFixesHelper(fileName: string, source: string, ruleFailures: RuleFailure[]) {
return super.applyFixes(fileName, source, ruleFailures);
}
}

const componentDeclaration = (templateUrl: string) =>
`import { Component } from '@angular/component';
@Component({
selector: 'foo-bar',
templateUrl: '${templateUrl}'
})
class SampleComponent {}
`;

const templateDeclaration =
`
<div>{{ foo }}</div>
`;

const templateDeclarationFixed =
`
<div></div>
`;

describe("Linter", () => {

it("apply fixes to correct files", () => {
const linter = new TestLinter({ fix: true });
const componentFile = createTempFile("ts");
const templateFile = createTempFile("ts");
fs.writeFileSync(componentFile, componentDeclaration(templateFile));
fs.writeFileSync(templateFile, templateDeclaration);
const sourceFile = createSourceFile(templateFile, `${templateDeclaration}`, ScriptTarget.ES2015);
const replacement = new Replacement(6, 9, "");
const failure = new RuleFailure(sourceFile, 6, 15, "Declaration doesn't exist", "foo-bar", replacement);
linter.applyFixesHelper(componentFile, componentDeclaration(templateFile), [failure]);
assert.equal(fs.readFileSync(templateFile), templateDeclarationFixed);
});

});

0 comments on commit 103dc03

Please sign in to comment.