-
Notifications
You must be signed in to change notification settings - Fork 889
Conversation
Thanks for your interest in palantir/tslint, @aminpaks! 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. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I left some suggestions to improve the algorithm.
Regarding failing CI: in addition to running yarn test
on your local machine you should also run yarn lint
and fix the reported failures. If you want all in one, you can use yarn verify
.
src/rules/spaceWithinParensRule.ts
Outdated
@@ -0,0 +1,167 @@ | |||
/** | |||
* @license | |||
* Copyright 2013 Palantir Technologies, Inc. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
2017
src/rules/spaceWithinParensRule.ts
Outdated
} | ||
|
||
private checkAndAddFailureAt(position: number, length: number, spaceCount: number = 0) { | ||
if (this.failures.some(f => f.getStartPosition().getPosition() === position)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do you really need to remove duplicate failures here? If yes, there's probably something wrong with the rule
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With your algorithm how should I know that if this is not the case below? Both open and close paren tokens will add a failure. this is the only place that we need to check.
console.log( );
~ [open token]
~ [close token]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
in my sample implementation there was a check if ch
is a line break to avoid failures.
When checking the CloseBrace, you could add a similar check if ch === 40
to not fail if you reached the OpenBraceToken.
src/rules/spaceWithinParensRule.ts
Outdated
} | ||
|
||
private getOpenParenToken(node: ts.Node): ts.Node | undefined { | ||
return Lint.childOfKind(node, ts.SyntaxKind.OpenParenToken); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if you do this for every node, you could just use forEachToken
from tsutils
to visit every token instead of visiting every node and finding the paren tokens.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
forEachToken
doesn't exist in tsutils v2.4.0
.
I tried import { forEachToken } from 'tsutils';
no luck.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
are you sure? I just tried it (v2.4.0) and it works for me.
Maybe it's another error, e.g. unused variable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah! it's utils
not tsutils
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
forEachToken
has this signature (fullText: string, kind: ts.SyntaxKind, pos: TokenPosition)
I'm using not using fullText
and Typescript is complaining. What should I do?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, I really meant import {forEachToken} from "tsutils"
. But the one in ../utils
is also ok.
Re unused parameter: either use fullText instead of
this.sourceFile.textor rename the parameter to
_fullText` (not the leading underscore)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nice!
@@ -0,0 +1,34 @@ | |||
// simple expression | |||
var x = [{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add a test for multiline call expression. This should pass IMO
foo(
bar,
baz,
);
src/rules/spaceWithinParensRule.ts
Outdated
optionsDescription: Lint.Utils.dedent` | ||
You may enforce the amount of whitespace within parentheses. | ||
`, | ||
options: { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
simplify to
options: {type: "number", min: 0}
@@ -0,0 +1,5 @@ | |||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
please rename the folder to nospace
or something like that since there is no default for this rule
src/rules/spaceWithinParensRule.ts
Outdated
|
||
private checkOpenParenToken(node: ts.Node) { | ||
const code = this.sourceFile.text.substr(node.getFullStart()); | ||
const matchResult = this.openingParenRegex.exec(code); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the regex solution seems a bit hacky and is not very easy to understand.
I'd prefer the following;
// pretending `node` is the OpenParenToken
let pos = node.end;
let ch = this.sourceFile.text.charCodeAt(pos);
while(ts.isWhiteSpaceSingleLine(ch)) {
++pos;
ch = this.sourceFile.text.charCodeAt(pos);
}
const whitespaceCount = pos - node.end;
if (this.options.size === 0) {
if (whitespaceCount !== 0)
// TODO addFailure
} else if (!ts.isLineBreak(ch) /* don't require whitespace when followed by line break */ && whitespaceCount !== this.options.size) {
// TODO fail
}
For the CloseParentToken you need a similar loop from node.pos - 1
backwards.
095d197
to
b3aa757
Compare
I forced push and applied all your comments/notes. |
1313d78
to
7c62a81
Compare
7c62a81
to
72d996a
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's getting better. But there are still some changes needed.
Please bear with me. The number of comments does not mean your code is bad
src/rules/spaceWithinParensRule.ts
Outdated
} | ||
|
||
private checkNode(node: ts.Node): void { | ||
forEachToken(node, (token: ts.Node) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I actually meant to replace the ts.forEachChild(...)
in walk
with this call.
You can just take this method's body and put it into walk
.
With the current implementation the rule will visit nested tokens multiple times.
src/rules/spaceWithinParensRule.ts
Outdated
}; | ||
/* tslint:enable:object-literal-sort-keys */ | ||
|
||
public static FAILURE_NO_SPACE = "No whitespace within parentheses"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you rephrase to Whitespace within parentheses is not allowed.
or similar?
src/rules/spaceWithinParensRule.ts
Outdated
/* tslint:enable:object-literal-sort-keys */ | ||
|
||
public static FAILURE_NO_SPACE = "No whitespace within parentheses"; | ||
public static FAILURE_NEEDS_SPACE = "Needs whitespace within parentheses"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Needs x spaces within parentheses.
++currentPos; | ||
currentChar = this.sourceFile.text.charCodeAt(currentPos); | ||
} | ||
if (!ts.isLineBreak(currentChar)) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if the rule is configured with 0 spaces, this condition will not show a warning for trailing whitespace right before a line break.
But that will be checked by trailing-whitespace
anyway, so it's not strictly necessary here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I though about it too.
src/rules/spaceWithinParensRule.ts
Outdated
} | ||
|
||
private checkCloseParenToken(tokenNode: ts.Node) { | ||
let currentPos = tokenNode.getStart() - 1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can be simplified to:
let currentPos = tokenNode.end - 2; // close paren token has a known width of 1, therefore node.getStart() === node.end - 1
Otherwise I would suggest to pass sourceFile
as parameter to getStart
for performance reasons.
src/rules/spaceWithinParensRule.ts
Outdated
}; | ||
} | ||
|
||
class SpaceWhitinParensWalker extends Lint.AbstractWalker<Options> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/Whitin/Within/
src/rules/spaceWithinParensRule.ts
Outdated
} | ||
|
||
public apply(sourceFile: ts.SourceFile): Lint.RuleFailure[] { | ||
return this.applyWithWalker(new SpaceWhitinParensWalker(sourceFile, this.ruleName, parseOptions(Number(this.ruleArguments[0])))); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
remove the Number(...)
, that's done by parseOptions
anyway
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
was getting Unsafe use of expression of type 'any'.
src/rules/spaceWithinParensRule.ts
Outdated
} | ||
} | ||
|
||
function parseOptions(whitespaceSize?: number): Options { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
change to whitespaceSize?: any
src/rules/spaceWithinParensRule.ts
Outdated
* it's already been caught by `checkOpenParenToken` | ||
*/ | ||
if (!ts.isLineBreak(currentChar) && currentChar !== 40) { | ||
const whitespaceCount = tokenNode.end - tokenNode.pos - 1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const whitespaceCount = token.end - currentPos - 2;
src/rules/spaceWithinParensRule.ts
Outdated
private checkCloseParenToken(tokenNode: ts.Node) { | ||
let currentPos = tokenNode.getStart() - 1; | ||
let currentChar = this.sourceFile.text.charCodeAt(currentPos); | ||
const allowdSpaceCount = this.options.size; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
allowedSpaceCount
c7d4352
to
74f70bb
Compare
I pushed a commit. Please review :) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM with minor nits
src/rules/spaceWithinParensRule.ts
Outdated
lintMsg = Rule.FAILURE_NEEDS_SPACE(allowedSpaceCount - whitespaceCount); | ||
const whitespace = " ".repeat(allowedSpaceCount - whitespaceCount); | ||
lintFix = Lint.Replacement.appendText(position, whitespace); | ||
} else if (whitespaceCount > allowedSpaceCount) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you don't need this if
, it's just the else branch
you can also remove the | undefined
from the type of the variables above
and you can remove the if (lintMsg !== undefined)
check below
src/rules/spaceWithinParensRule.ts
Outdated
} | ||
} | ||
|
||
private AddFailureAtWithFix(position: number, length: number, whitespaceCount: number = 0) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
method names should be lowerCamelCase
src/rules/spaceWithinParensRule.ts
Outdated
} | ||
} | ||
|
||
private AddFailureAtWithFix(position: number, length: number, whitespaceCount: number = 0) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the default value for parameter whitespaceCount
should not be necessary
Done |
Merging this PR, because it's open for quite some time, code looks good and there was no objection. Thanks @aminpaks! |
PR checklist
Overview of change:
Adds new rule to verify amount of whitespace within parentheses.
Is there anything you'd like reviewers to focus on?
Everything.
CHANGELOG.md entry:
[new-rule]
space-within-parens