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

Add text replacement fixes for rules #1423

Merged
merged 7 commits into from
Aug 4, 2016
Merged

Conversation

ScottSWu
Copy link
Contributor

@ScottSWu ScottSWu commented Jul 21, 2016

  • Created IFix and IReplacement structures for representing fixes
    • programWalker includes createFix and createReplacement
  • Added optional parameter to createFailure for suggesting fixes
  • Modified semicolon rule to suggest fixes (add / remove semicolon)
  • Modified testing to check against a file with fixes applied
    • If there is a ".ts.fix" file, then the test will take the first suggested fix and apply to the test file (without markup) and compare

Addresses #561

@jkillian
Copy link
Contributor

@alexeagle, do you plan to review this? I doubt I'll be able to get to this until sometime next week at the earliest. Definitely a great feature I want to get implemented!

@ScottSWu
Copy link
Contributor Author

cc: @mprobst

@alexeagle
Copy link
Contributor

I've reviewed it on Scott's branch. I'll take another pass here, but the design already LGTM

if (stat.isFile()) {
fixedFileText = fs.readFileSync(fixedFile, "utf8");
// accumulate replacements
const replacements = failures.reduce((acc, failure) => {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure the reduce here is worth the syntactic and cognitive cost, it might be simpler to just iterate?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

constructor(private start: number, private length: number, private text: string) {
}

public getStart() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd be fine with making all of these real get methods. I find that this sort of method can get frustrating (but fine either way)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@jkillian
Copy link
Contributor

Looking good @ScottSWu.

Is the Replacement API robust enough? How tricky to use is it when you get into weird changes, like overlapping fixes? What about when multiple rules want to apply fixes to the same file? I know you looked into the way it's done in other similar tools.

Also, a test or two for your new test code would be great if possible! You could just add it to test/check-bin.sh

@alexeagle
Copy link
Contributor

Applying fixes from multiple rules at once sounds like trouble to me. In the worst case, two rules may conflict, and after applying one set of replacements, you are left with some that don't apply, and now the result isn't even syntactically valid.
I think we'd have to apply the fixes (either to the filesystem or an in-memory buffer) after running one rule, then take the result and pass it to the next rule. You may get different results depending on the order the rules are executed.

Within a single rule, I'm not sure there is a need for overlapping fixes. Fixes should prepend or append text where possible, rather than replacing a whole range (and it's hard to convert an AST subtree to text anyway)

@ScottSWu
Copy link
Contributor Author

ScottSWu commented Jul 29, 2016

To add on a bit, no these replacement functions are not robust, but would be building blocks for an something that is. A single fix should not have overlapping replacements within itself, but also should be applied entirely or not at all (e.g. it doesn't make sense to replace one quote mark). Thus the Fix.apply and the Replacement.apply functions will be useful.

From what ESLint does, fixes are automatically applied, and only fixes that failed to be applied are displayed.

EDIT:
This current PR doesn't include the CLI options, since we first wanted to figure out how to decide which rules to apply, and how to apply them. Are there other tests that would go in check-bin.sh?

* Created IFix and IReplacement structures for representing fixes
  * programWalker includes createFix and createReplacement
* Added optional parameter to createFailure for suggesting fixes
* Modified semicolon rule to suggest fixes
* Modified testing to check against a file with fixes applied
- Replaced reduce with for loop
- Changed Fix and Replacement to classes
  - Added apply method to each
  - Fix.apply applies all replacements in reverse order
  - Replacement.apply performs the text substitution
- Added function to display diff results in the tester
@alexeagle
Copy link
Contributor

Ping @jkillian - Scott's internship has only a couple more weeks so we'd like to get this moving

@@ -82,6 +82,14 @@ export class RuleWalker extends SyntaxWalker {
}
}

public createFix(replacements: Replacement[]): Fix {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I went back and forth on if we should have these wrapper methods at all (as the constructors have the exact same functionality). Do you think it makes sense to have them?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd prefer to expose only the typical fix methods. These are what we need for the current check and expose less API details to all the rules that might start using it.

so far we need
appendText(n: node, t: text) for putting a semicolon after the statement, and
delete(start: number, length: number) for deleting a semicolon?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fix is probably redundant. Eventually we should proxy replacements (including createReplacement) to make sure replacements at the same spots are applied in the right order. It turns out sorting is not guaranteed to be stable, but adding an additional ordering counter breaks ties correctly.


public apply(content: string) {
// sort replacements in reverse so that diffs are properly applied
this.innerReplacements.sort((a, b) => b.end - a.end);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm thinking we could have a Replacements.applyAll that is parallel to Fix.applyAll?

@jkillian
Copy link
Contributor

jkillian commented Aug 3, 2016

@ScottSWu As far as check-bin tests, I was thinking perhaps something like here just to make sure that the code paths dealing with .fix have a test that specifically hits them.

@jkillian
Copy link
Contributor

jkillian commented Aug 3, 2016

This is looking good though, I think we can merge this shortly. @ScottSWu, @alexeagle what do you plan to proceed with after this merges? Implementing fixes for more rules?

@ScottSWu
Copy link
Contributor Author

ScottSWu commented Aug 3, 2016

Got it, added a passing and failing check-bin tests.

I believe the next step is to add the --fix option to the CLI. Implementing more fixes for rules is definitely important. There's also adding more helper functions for creating replacements, and outputting fixes in the other formatters.

@jkillian
Copy link
Contributor

jkillian commented Aug 4, 2016

Sweet, future plans sound good to me. Merged this so things can more easily continue!

@jkillian jkillian merged commit fc9a72d into palantir:master Aug 4, 2016
@ScottSWu
Copy link
Contributor Author

ScottSWu commented Aug 4, 2016

Awesome! Thanks for pushing this through!

soniro pushed a commit to soniro/tslint that referenced this pull request Aug 31, 2016
* Created IFix and IReplacement structures for representing fixes
  * programWalker includes createFix and createReplacement
* Added optional parameter to createFailure for suggesting fixes
* Modified semicolon rule to suggest fixes (add / remove semicolon)
* Modified testing to check against a file with fixes applied
  * If there is a ".ts.fix" file, then the test will take the first suggested fix and apply to the test file (without markup) and compare

Addresses palantir#561
@nchen63 nchen63 added this to the TSLint v4.0 milestone Nov 8, 2016
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants