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

Added space-before-function-paren rule #1897

Merged
merged 1 commit into from Dec 24, 2016

Conversation

cameron-mcateer
Copy link
Contributor

@cameron-mcateer cameron-mcateer commented Dec 18, 2016

PR checklist

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

What changes did you make?

I added a rule which lets you enforce whether a space should exist or not before the opening parenthesis of a named function, anonymous function, async arrow function, method, or constructor. This is meant to be similar to the same-named rule for eslint.

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

  • Performance of rule evaluation (specifically the use of a ts.Scanner for checking spaces before parenthesis).
  • The completeness of the tests

@palantirtech
Copy link
Member

Thanks for your interest in palantir/tslint, @cameron-mcateer! 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.

@nchen63
Copy link
Contributor

nchen63 commented Dec 19, 2016

can you turn on circleCI?

@cameron-mcateer
Copy link
Contributor Author

cameron-mcateer commented Dec 19, 2016

Sorry I am new to contributing to tslint and can't find anything anything enabling circleCI. Do you have a link?
@nchen63 circleCI complete

import * as Lint from "../index";

const ALWAYS_OR_NEVER = {
enum: ["always", "never"],
Copy link
Contributor

Choose a reason for hiding this comment

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

please use 4-space indentation in TS files like the rest of the project

super.visitMethodSignature(node);
}

private _visitFunction(node: ts.Node): void {
Copy link
Contributor

Choose a reason for hiding this comment

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

we don't use the underscore naming convention -- the private modifier is enough to denote encapsulation.

failure = this.createFailure(openParen.getStart(), 1, Rule.MISSING_WHITESPACE_ERROR, fix);
}

if (failure) {
Copy link
Contributor

Choose a reason for hiding this comment

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

please avoid implicit type coercion to boolean -- do an explicit undefined check instead

private _visitFunction(node: ts.Node): void {
const options = this.getOptions();

if (options === null || options.length === 0 || Object.keys(options).length === 0) {
Copy link
Contributor

Choose a reason for hiding this comment

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

this check looks overly defensive; I don't think any of your code will break if you remove this. it's better to be consistent with other rules in code style.

private getOption(option: string): string {
const allOptions = this.getOptions();
if (allOptions == null || allOptions.length === 0) {
return null;
Copy link
Contributor

Choose a reason for hiding this comment

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

please avoid using null explicitly; return undefined instead

}
});

if (!openParen || (isArrow && !isAsyncArrow)) {
Copy link
Contributor

Choose a reason for hiding this comment

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

no implicit boolean coercion

type: "style",
typescriptOnly: false,
};
public static INVALID_WHITESPACE_ERROR = "Should be no space before paren";
Copy link
Contributor

Choose a reason for hiding this comment

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

suggestion: "Spaces before function parens are disallowed"

typescriptOnly: false,
};
public static INVALID_WHITESPACE_ERROR = "Should be no space before paren";
public static MISSING_WHITESPACE_ERROR = "Should be a space before paren";
Copy link
Contributor

Choose a reason for hiding this comment

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

suggestion: "Missing whitespace before function parens"

@cameron-mcateer
Copy link
Contributor Author

@adidahiya Thanks for the feedback! Changes made.

@cameron-mcateer
Copy link
Contributor Author

Updated. Renamed file from test.js.int to test.js.lint.


* \`"anonymous"\` checks before the opening paren in anonymous functions
* \`"named"\` checks before the opening paren in named functions
* \`"asyncArrow"\` checks before the opening paren in async arrow functions,
Copy link
Contributor

Choose a reason for hiding this comment

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

don't need comma at the end here

super.visitMethodSignature(node);
}

private visitFunction(node: ts.Node): void {
Copy link
Contributor

Choose a reason for hiding this comment

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

can you break this up into smaller functions?

export class Rule extends Lint.Rules.AbstractRule {
public static metadata: Lint.IRuleMetadata = {
description: "Require or disallow a space before function parenthesis",
optionExamples: [`[true, {"anonymous": "always", "named": "never", "asyncArrow": "always"}]`],
Copy link
Contributor

Choose a reason for hiding this comment

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

seems tedious to need to specify a value for each type of function. How about allowing something like [true, "always"] or even [true], which defaults to the same thing.

@adidahiya adidahiya dismissed their stale review December 20, 2016 01:10

deferring to @nchen63 for final review

@cameron-mcateer
Copy link
Contributor Author

@nchen63 Split visitFunction() into multiple functions and moved location of failure to the space character for "never" failures.

* \`"named"\` checks before the opening paren in named functions
* \`"asyncArrow"\` checks before the opening paren in async arrow functions
* \`"method"\` checks before the opening paren in class methods
*v\`"constructor"\` checks before the opening paren in class constructors
Copy link
Contributor

Choose a reason for hiding this comment

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

stray v?

}

private getOption(optionName: string): string {
const allOptions = this.getOptions();
Copy link
Contributor

Choose a reason for hiding this comment

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

can you parse the options once in the constructor so that doing this check will be a quick lookup?

@cameron-mcateer
Copy link
Contributor Author

@nchen63 Woops sorry that snuck in. Also caching the options now.

@cameron-mcateer
Copy link
Contributor Author

Rebased on latest to keep tests passing.


class FunctionWalker extends Lint.RuleWalker {
private scanner: ts.Scanner;
private cachedOptions: any;
Copy link
Contributor

Choose a reason for hiding this comment

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

here's how you can avoid using any for cachedOptions:

interface CachedOptions {
    anonymous?: boolean;
    asyncArrow?: boolean;
}
type optionType = "anonymous" | "asyncArrow";
let cachedOptions: CachedOptions = {};

// cache the options
let optionArray: optionType[] = ["anonymous", "asyncArrow"]
for (const option of optionArray) {
    cachedOptions[option] = true;
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Oh thank you. I kept using the string values in so that it allows the user to ignore certain rules (as opposed to forcing a failure if they are not consistent).

@nchen63 nchen63 merged commit 60e55d6 into palantir:master Dec 24, 2016
@nchen63
Copy link
Contributor

nchen63 commented Dec 24, 2016

@cameron-mcateer thanks!

For future reference, it would be helpful if you didn't squash and force push your changes so I can see the diff between updates.

@cameron-mcateer
Copy link
Contributor Author

@nchen63 Thanks! Will do. I'm used to amending all my PR commits. I'll keep that in mind from now on.

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

4 participants