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

New Rule: newline-before-return #2173

Merged
merged 7 commits into from Feb 7, 2017

Conversation

artursvonda
Copy link
Contributor

@artursvonda artursvonda commented Feb 3, 2017

PR checklist

  • Addresses an existing issue:
  • New feature, bugfix, or enhancement
  • Includes tests
  • Documentation update

What changes did you make?

A new rule to force blank lines before return. Based on http://eslint.org/docs/rules/newline-before-return

Is there anything you'd like reviewers to focus on?

Making sure all test cases are covered. I took the base file from eslint and added a few cases.

[new-rule] newline-before-return

@palantirtech
Copy link
Member

Thanks for your interest in palantir/tslint, @artursvonda! Before we can accept your pull request, you need to sign our contributor license agreement - just visit https://cla.palantir.com/ and follow the instructions. Once you sign, I'll automatically update this pull request.


private getIndex(node: ts.Node) {
const children = node.parent ? node.parent.getChildren() : [];
// For some reason instances are not the same and indexOf doesn't work with given node directly
Copy link
Contributor

Choose a reason for hiding this comment

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

getChildren does not return what you expect, that's why indexOf does not work here:

node.parent is either ts.BlockLike or ts.IfStatement, ts.IterationStatement, ...
If it is not ts.BlockLike the return statement is the only child, e.g. an if statement without a block and only a single return statement. So you don't have to call getChildren.
If it is ts.BlockLike getChildren will return [OpenBraceToken, SyntaxList, CloseBraceToken] where SyntaxList is an array of statements within the block. But you don't need this SyntaxList, because BlockLike has a statements property (which also contains all statements, duh)

here is a simpler solution:

private getIndex(node: ts.Node) {
  const parent = node.parent!; // use ! (non null assertion) because we know every node has a parent (except ts.SourceFile)
  if (isBlockLike(parent) {
    return parent.statements.indexOf(node);
  } {
    // `node` is the only statement within this "block scope" -> do whatever you need to do in this case
  }
}
...
function isBlockLike(node: ts.Node): node is ts.BlockLike {
    return "statements" in node; // could also be node.kind === ts.SyntaxKind.Block || node.kind === ts.SyntaxKind.CaseClause || to be continued ...
}

const position = source.getPositionOfLineAndCharacter(line - 1, 0);
const end = source.getPositionOfLineAndCharacter(line, 0) - 1;
const all = source.getText().substr(position, end - position);
const trimmed = all.replace(/\s+/, "");
Copy link
Contributor

Choose a reason for hiding this comment

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

you could also just use all.search(/\S/) !== -1

super.visitReturnStatement(node);

let start = node.getStart();
const comments = ts.getLeadingCommentRanges(node.getSourceFile().text, node.getFullStart());
Copy link
Contributor

Choose a reason for hiding this comment

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

use this.getSourceFile() instead of node.getSourceFile()
the latter walks up the whole AST until it finds the SourceFile, which is unnecessary work

Check for block-like parent to better understand return's position within parent
@artursvonda
Copy link
Contributor Author

Thanks @ajafff for all the comments and suggestions. I addressed those comments and simplified the code a bit.


private validateBlankLine(line: number) {
const source = this.getSourceFile();
const position = source.getPositionOfLineAndCharacter(line - 1, 0);
Copy link
Contributor

@nchen63 nchen63 Feb 7, 2017

Choose a reason for hiding this comment

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

what would happen there was a return on the first line?

does this handle other cases where someone writes a return statement on the same line as another statement?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good point. Not sure how that should be handled. Any ideas/suggestions? Meanwhile I'll add a test case.

@nchen63
Copy link
Contributor

nchen63 commented Feb 7, 2017

I'm leaning toward always flagging if there's another statement on the same line as the return statement

@artursvonda
Copy link
Contributor Author

@nchen63 Yeah, makes sense. The idea is that return should have spacing around it so it's clear and easier to spot and read. So the rule basically is "if the return is not the first thing in the block, there should be blank line before it.". With that in mind I simplified the code a bit more. Also changed the position of the error a bit and now it's at the start of the return statement.

@nchen63 nchen63 merged commit 44f74e9 into palantir:master Feb 7, 2017
@nchen63
Copy link
Contributor

nchen63 commented Feb 7, 2017

@artursvonda thanks!

@nchen63
Copy link
Contributor

nchen63 commented Feb 7, 2017

@artursvonda this rule is a good candidate for an auto fixer too

@artursvonda
Copy link
Contributor Author

@nchen63 No problem. And yeah, will see if I can add the fixed over some evening.

@glen-84
Copy link
Contributor

glen-84 commented Jul 2, 2017

This should probably have been called blank-line-before-return.

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.

None yet

5 participants