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

refactor newlineBeforeReturn to support more variants #3139

Closed
wants to merge 2 commits into from

Conversation

CSchulz
Copy link
Contributor

@CSchulz CSchulz commented Aug 18, 2017

PR checklist

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

Overview of change:

Rename newlineBeforeReturn to newline and add some more options for adding newlines.

@ajafff
Copy link
Contributor

ajafff commented Aug 18, 2017

I agree that it makes sense to rename and enhance the rule instead of adding yet another whitespace related rule. Nevertheless we need to keep newline-before-return around until the next major version to avoid a breaking change.
But that's pretty easy. Just export the walker of your new rule and use it from newline-before-return with the configuration to only require a blank line before return statements.
Also add a deprecation message to the metadata of newline-before-return

Copy link
Contributor

@ajafff ajafff left a comment

Choose a reason for hiding this comment

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

Finished my first pass of the review. I only looked at the code. Will need to think a bit more about the configuration.

}

const ALWAYS_IGNORE_OR_NEVER = {
enum: OptionState,
Copy link
Contributor

Choose a reason for hiding this comment

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

this is only used in the metadata? I don't think this works with string enums. It actually expects a string array here.

options[optionName] = typeof json === "object" ? json[optionName] : json === undefined ? "always" : json;
}
return options;
}
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 suggest the following (note that this defaults to ignore, which might be more intuitive)

type Options = Record<OptionName, Option>;
function parseOptions(json: Partial<Options> | undefined) {
    const default: Options = {return: "ignore", class: "ignore", functionBlock: "ignore", block: "ignore"};
    return {...default, json};
}

optionsDescription: Lint.Utils.dedent`
Following arguments may be optionally provided:

* \`"return"\` checks for empty line before return when not the only line in the block.
Copy link
Contributor

Choose a reason for hiding this comment

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

s/line/statement/

Following arguments may be optionally provided:

* \`"return"\` checks for empty line before return when not the only line in the block.
* \`"class"\` checks for empty line after class declaration.
Copy link
Contributor

Choose a reason for hiding this comment

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

checks for empty line at the start of a class body


* \`"return"\` checks for empty line before return when not the only line in the block.
* \`"class"\` checks for empty line after class declaration.
* \`"functionBlock"\` checks for empty line after function block declaration.
Copy link
Contributor

Choose a reason for hiding this comment

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

at the start of a function block


if (isClassDeclaration(node) && this.options.class != OptionState.ignore) {
this.checkForEmptyLine(
getChildOfKind(node, ts.SyntaxKind.OpenBraceToken, this.sourceFile)!, node.members[0],
Copy link
Contributor

Choose a reason for hiding this comment

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

instead of getChildOfKind(...) you could simply pass node.members.pos as first parameter. see my other comment in checkForEmptyLine below

(isFunctionWithBody(node.parent!) && this.options.functionBlock != OptionState.ignore
|| this.options.block != OptionState.ignore)) {
this.checkForEmptyLine(
node.getChildAt(0), node.statements[0], this.options.functionBlock == OptionState.always, 'first statement',
Copy link
Contributor

Choose a reason for hiding this comment

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

instead of node.getChildAt(...) you could simply pass node.statements.pos as first parameter. see my other comment in checkForEmptyLine below

(isFunctionWithBody(node.parent!) && this.options.functionBlock != OptionState.ignore
|| this.options.block != OptionState.ignore)) {
this.checkForEmptyLine(
node.getChildAt(0), node.statements[0], this.options.functionBlock == OptionState.always, 'first statement',
Copy link
Contributor

Choose a reason for hiding this comment

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

you need to check if the block contains any statement

private checkForEmptyLine(node: ts.Node, firstNode: ts.Node, lineRequired: boolean, nodeType: string) {
let start = node.end;
let line = ts.getLineAndCharacterOfPosition(this.sourceFile, start).line;
let firstNodeStart = firstNode.getStart();
Copy link
Contributor

Choose a reason for hiding this comment

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

please provide the sourceFile parameter to getStart() for performance reasons


[0]: Missing blank line before return


Copy link
Contributor

Choose a reason for hiding this comment

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

do these trailing whitespaces serve a purpose?

optionsDescription: Lint.Utils.dedent`
Following arguments may be optionally provided:

* \`"return"\` checks for empty listane before return when not the only statement in the block.
Copy link
Contributor

Choose a reason for hiding this comment

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

s/listane/line/

* \`"return"\` checks for empty listane before return when not the only statement in the block.
* \`"class"\` checks for empty line at the start of a class body.
* \`"functionBlock"\` checks for empty line at the start of a function block.
* \`"block"\` checks for empty line after block declaration.`,
Copy link
Contributor

Choose a reason for hiding this comment

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

s/after/in the first line of a/


export enum ViolationType {
needed = "needed",
needless = "needless",
Copy link
Contributor

Choose a reason for hiding this comment

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

prefer "unnecessary"

optionsDescription: Lint.Utils.dedent`
Following arguments may be optionally provided:

* \`"return"\` checks for empty listane before return when not the only statement in the block.
Copy link
Contributor

Choose a reason for hiding this comment

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

as discussed offline: I don't like the option names.
I'd prefer "before-return" here.
I'm also in favor of "start-of-class" to allow adding "before-class" and "after-class" later on.

And to keep naming consistent, you should prefer "function-block" over "functionBlock"

/* tslint:enable:object-literal-sort-keys */

public static FAILURE_STRING_FACTORY(kind: ViolationType, nodeType: string) {
const kindMsg = kind === ViolationType.needed ? 'Missing' : 'Unneeded';
Copy link
Contributor

Choose a reason for hiding this comment

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

Why don't you use the string value of the enum?

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants