Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add support to convert lambda to function and vice-versa #28250

Merged
merged 38 commits into from
Jun 1, 2020

Conversation

D0nGiovanni
Copy link
Contributor

Fixes #23299

@msftclas
Copy link

msftclas commented Oct 31, 2018

CLA assistant check
All CLA requirements met.

Copy link

@ghost ghost left a comment

Choose a reason for hiding this comment

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

It would be nice to extend this to allow arbitrary function expressions to be converted to arrow functions, as long as their name (if it exists) isn't used. You can use FindAllReferences.isSymbolReferencedInFile to determine whether the name is used.


function getFunctionInfo(file: SourceFile, startPosition: number): FunctionInfo | undefined {
const token = getTokenAtPosition(file, startPosition);
let maybeFunc;
Copy link

Choose a reason for hiding this comment

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

This could just be two different variables, one for each time it's assigned to.

let maybeFunc;

maybeFunc = getArrowFunctionFromVariableDeclaration(token.parent);
if (!!maybeFunc) return { selectedVariableDeclaration: true, func: maybeFunc };
Copy link

Choose a reason for hiding this comment

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

No need to have !! for the condition of an if, it automatically booleanifies everything.

return getEditInfoForConvertToArrowFunction(context, func);

default:
Debug.fail("invalid action");
Copy link

Choose a reason for hiding this comment

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

You can just return Debug.fail("Invalid action"); since it returns never.


function getEditInfoForConvertToArrowFunction(context: RefactorContext, func: FunctionExpression | ArrowFunction): RefactorEditInfo | undefined {
const { file } = context;
if (!isFunctionExpression(func)) return undefined;
Copy link

@ghost ghost Nov 1, 2018

Choose a reason for hiding this comment

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

The parameter type should just be FunctionExpression then?

}

function canBeConvertedToExpression(body: Block, head: Statement): head is ReturnStatement | ExpressionStatement {
return body.statements.length === 1 && ((isReturnStatement(head) && !!head.expression) || isExpressionStatement(head));
Copy link

Choose a reason for hiding this comment

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

Not sure about the last condition there. () => foo() has a different type from () => { foo(); }.

Copy link
Contributor

Choose a reason for hiding this comment

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

you're right.
to clarify

let epsilon = () => "epsilon";
let foo = () => epsilon()       // foo: () => string
let bar = () => { epsilon() }   // bar: () => void

body = func.body;
}

const newNode = createArrowFunction(func.modifiers, func.typeParameters, func.parameters, func.type, /* equalsGreaterThanToken */ undefined, body);
Copy link

Choose a reason for hiding this comment

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

Suprised this works without the token -- seems like it would be better to createToken(SyntaxKind.EqualsGreaterThanToken) even if the emitter doesn't currently require it.

const body = convertToBlock(func.body);
const newNode = createFunctionExpression(func.modifiers, func.asteriskToken, /* name */ undefined, func.typeParameters, func.parameters, func.type, body);
const edits = textChanges.ChangeTracker.with(context, t => t.replaceNode(file, func, newNode));
return { renameFilename: undefined, renameLocation: undefined, edits };
Copy link

Choose a reason for hiding this comment

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

It may be better for these functions to just return the edits, and some outer function to wrap them in RefactorEditInfo.

@ghost ghost mentioned this pull request Nov 13, 2018
@bigaru
Copy link
Contributor

bigaru commented Jan 23, 2019

Hi @andy-ms
A friend pointed out that this behaves differently in function than in lambda.

I've solved that using forEachChild to detect whether a body contains a this. I find my solution suboptimal because if the body is large, then it will also take time to detect this. However, the computation for getAvailableActions should be quick.

Are the any auxiliary function which can provide a better way to solve this?

@ghost
Copy link

ghost commented Jan 23, 2019

@bigaru Make sure you're not testing any nested functions or classes, which would come with their own meaning of this anyway. If you're not descending into inner functions then I would expect forEachChild wouldn't be too slow.
CC @sandersn @DanielRosenwasser for review

@jessetrinity
Copy link
Contributor

@D0nGiovanni if you are still interested in this PR I would like to get it in once the merge conflicts are resolved. Thanks!

@D0nGiovanni
Copy link
Contributor Author

@jessetrinity Alright! I should have it done by the end of the weekend.

@bigaru
Copy link
Contributor

bigaru commented May 27, 2020

When @D0nGiovanni told me, I was so excited that I resolved the conflicts.

Thanks @jessetrinity for your effort!

@jessetrinity jessetrinity merged commit 1d1c167 into microsoft:master Jun 1, 2020
@jessetrinity
Copy link
Contributor

@D0nGiovanni @bigaru thank you for the contribution to TypeScript!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
For Backlog Bug PRs that fix a backlog bug
Projects
Archived in project
Development

Successfully merging this pull request may close these issues.

CodeAction: convert lambda expression declaration to function
6 participants