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

[enhancement] object-literal-shorthand / config to disallow shorthand #3268

Merged
merged 8 commits into from Oct 3, 2017

Conversation

aervin
Copy link
Contributor

@aervin aervin commented Oct 1, 2017

PR checklist

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

Overview of change:

Can pass argument "never" to object-literal-shorthand rule to disallow shorthand syntax. Currently, default is "always".

}
}

function walk(ctx: Lint.WalkContext<void>) {
function walk(ctx: Lint.WalkContext<Options>) {
Copy link
Contributor

Choose a reason for hiding this comment

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

The branches for both options don't share any code. Consider splitting into two separate functions. That will make it easier to understand and avoids unnecessary CPU cycles.

if (isPropertyAssignment(node)) {
if (node.name.kind === ts.SyntaxKind.Identifier &&
if (isShorthandAssignment(node) && !allowShorthandAssignments) {
ctx.addFailureAtNode(node, Rule.SHORTHAND_ASSIGNMENT);
Copy link
Contributor

Choose a reason for hiding this comment

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

fixing the shorthand to longhand syntax shouldn't be too hard I guess

name: ts.PropertyName,
initializer: ts.FunctionExpression,
sourceFile: ts.SourceFile,
): [string, Lint.Fix] {
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 all these purely stylistic changes. They don't add any value to the PR and make the diff harder to reason about.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think I have a TS formatter formatting on save. I'll take care of it.

function fixShorthandToLonghand(node: ts.ShorthandPropertyAssignment | ts.MethodDeclaration): Lint.Fix {
let replacementText = isMethodDeclaration(node)
? ": function"
: `: ${node.name.getText()}`;
Copy link
Contributor

Choose a reason for hiding this comment

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

you can use node.name.text here

function walk(ctx: Lint.WalkContext<void>) {
function walk(ctx: Lint.WalkContext<Options>) {
const { options: { allowShorthandAssignments } } = ctx;
allowShorthandAssignments ? enforceShorthand(ctx) : disallowShorthand(ctx);
Copy link
Contributor

Choose a reason for hiding this comment

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

you can also do that in Rule#apply:

this.applyWithFunction(sourceFile, this.ruleArguments.indexOf(OPTION_NEVER) === -1 ? enforceShorthand : disallowShorthand);

@@ -63,6 +103,19 @@ function walk(ctx: Lint.WalkContext<void>) {
});
}

function fixShorthandToLonghand(node: ts.ShorthandPropertyAssignment | ts.MethodDeclaration): Lint.Fix {
let replacementText = isMethodDeclaration(node) ? ": function" : `: ${node.name.getText()}`;
Copy link
Contributor

Choose a reason for hiding this comment

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

you can substitute node.name.getText() with node.name.text


const asyncFn = {
foo: async function() {},
bar: async function*() {}
Copy link
Contributor

Choose a reason for hiding this comment

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

needs a test for async shorthand

if (isGeneratorFunction(node)) {
const asteriskPosition = (node as ts.MethodDeclaration).asteriskToken!.getStart();
fixes.push(Lint.Replacement.replaceFromTo(asteriskPosition, asteriskPosition + 1, ""));
}
Copy link
Contributor

Choose a reason for hiding this comment

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

needs special handling for async methods as well.

before you do that, just a suggestion to simplify the fix: replace the name with the function keyword and insert the name plus the colon at the start of the declaration.
That way you don't have to handle the async keyword or the asterisk at all

@@ -204,7 +204,7 @@ export const rules = {
"no-unnecessary-type-assertion": true,
"number-literal-format": true,
"object-literal-key-quotes": [true, "consistent-as-needed"],
"object-literal-shorthand": true,
"object-literal-shorthand": [true, "always"],
Copy link
Contributor

Choose a reason for hiding this comment

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

With the current implementation "always" is not a valid option.

@aervin
Copy link
Contributor Author

aervin commented Oct 2, 2017

I'm struggling to simplify the fixer function b/c of this case:

var obj4 = {
  async* f() {
   yield 1;
   yield 2;
   yield 3;
  }
};

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.

almost done

let
replacementStart = (isAsync && node.modifiers !== undefined) ? getModifier(node, ts.SyntaxKind.AsyncKeyword)!.getStart() : -1;
replacementStart = (isGenerator && !isAsync) ? (node as ts.MethodDeclaration).asteriskToken!.getStart() : -1;
replacementStart = replacementStart === -1 ? node.name.getStart() : replacementStart;
Copy link
Contributor

Choose a reason for hiding this comment

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

the async keyword is the only modifier allowed here, so replacementStart can always be node.getStart()

`${node.name.getText()}:${isAsync ? " async" : ""} function${isGenerator ? "*" : ""}`,
)
/* tslint:disable:trailing-comma */
: Lint.Replacement.appendText(node.name.getStart(), `${node.name.text}: `)
Copy link
Contributor

Choose a reason for hiding this comment

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

consider moving the fix for ShorthandPropertyAssignment out of the function. It will make many conditions and type assertions unnecessary

function isShorthandAssignment(node: ts.Node): boolean {
return (
isShorthandPropertyAssignment(node) ||
(isMethodDeclaration(node) && node.parent !== undefined ? node.parent.kind === ts.SyntaxKind.ObjectLiteralExpression : false)
Copy link
Contributor

Choose a reason for hiding this comment

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

node.parent cannot be undefined
also no need for the conditional expression, just use &&

x: x
}
};
[OBJECT_LITERAL_DISALLOWED]: Shorthand property assignments have been disallowed.
Copy link
Contributor

Choose a reason for hiding this comment

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

please add a test case with class methods. these should be ignored by the rule

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You mean class members which instantiate object literals with shorthand props?

Copy link
Contributor

Choose a reason for hiding this comment

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

I mean regular method declarations inside a class. They are ignored by the rule. I just want a test to ensure this won't regress.

class C {
    doStuff() {} // shouldn't be an error
}

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ahh of course. Thanks

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.

LGTM with a suggestion

return ts.forEachChild(ctx.sourceFile, function cb(node): void {
if (isShorthandAssignment(node)) {
ctx.addFailureAtNode(
node,
Copy link
Contributor

Choose a reason for hiding this comment

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

looking at the tests, I think it's better to just show the error at node.name

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Went ahead and updated the error messages for shorthand-only too

@ajafff
Copy link
Contributor

ajafff commented Oct 3, 2017

Went ahead and updated the error messages for shorthand-only too

I was just about to comment on that. I think showing the error only at the name is a bit too narrow for those errors.
If you revert that, I think this PR is good to go. Sorry for the back and forth.

@aervin
Copy link
Contributor Author

aervin commented Oct 3, 2017

Haha maybe a bit presumptuous on my part. Anyway, we made it! Thanks as always for your help/patience.

@ajafff ajafff merged commit dfc444b into palantir:master Oct 3, 2017
@ajafff
Copy link
Contributor

ajafff commented Oct 3, 2017

Thanks @aervin

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

2 participants