Skip to content

Commit

Permalink
Showing 6 changed files with 179 additions and 0 deletions.
22 changes: 22 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -88,6 +88,7 @@
"onCommand:abracadabra.addBracesToIfStatement",
"onCommand:abracadabra.bubbleUpIfStatement",
"onCommand:abracadabra.convertForToForeach",
"onCommand:abracadabra.convertFunctionDeclarationToArrowFunction",
"onCommand:abracadabra.convertIfElseToTernary",
"onCommand:abracadabra.convertIfElseToSwitch",
"onCommand:abracadabra.convertSwitchToIfElse",
@@ -143,6 +144,11 @@
"title": "Convert For-Loop To ForEach",
"category": "Abracadabra"
},
{
"command": "abracadabra.convertFunctionDeclarationToArrowFunction",
"title": "Convert Function Declaration To Arrow Function",
"category": "Abracadabra"
},
{
"command": "abracadabra.convertIfElseToTernary",
"title": "Convert If/Else to Ternary",
@@ -393,6 +399,22 @@
"command": "abracadabra.convertForToForeach",
"when": "editorLangId == typescriptreact"
},
{
"command": "abracadabra.convertFunctionDeclarationToArrowFunction",
"when": "editorLangId == javascript"
},
{
"command": "abracadabra.convertFunctionDeclarationToArrowFunction",
"when": "editorLangId == javascriptreact"
},
{
"command": "abracadabra.convertFunctionDeclarationToArrowFunction",
"when": "editorLangId == typescript"
},
{
"command": "abracadabra.convertFunctionDeclarationToArrowFunction",
"when": "editorLangId == typescriptreact"
},
{
"command": "abracadabra.convertIfElseToTernary",
"when": "editorLangId == javascript"
4 changes: 4 additions & 0 deletions src/editor/error-reason.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
export { ErrorReason, toString };

enum ErrorReason {
DidNotFindFunctionDeclarationToConvert,
DidNotFindLetToConvertToConst,
DidNotFindSwitchToConvert,
DidNotFindJsxAttributeToAddBracesTo,
@@ -45,6 +46,9 @@ enum ErrorReason {

function toString(reason: ErrorReason): string {
switch (reason) {
case ErrorReason.DidNotFindFunctionDeclarationToConvert:
return didNotFind("a function declaration to convert");

case ErrorReason.DidNotFindLetToConvertToConst:
return didNotFind(
"a variable declared as let that could be converted to const"
3 changes: 3 additions & 0 deletions src/extension.ts
Original file line number Diff line number Diff line change
@@ -7,6 +7,7 @@ import addBracesToArrowFunction from "./refactorings/add-braces-to-arrow-functio
import addBracesToIfStatement from "./refactorings/add-braces-to-if-statement";
import bubbleUpIfStatement from "./refactorings/bubble-up-if-statement";
import convertForToForeach from "./refactorings/convert-for-to-foreach";
import convertFunctionDeclarationToArrowFunction from "./refactorings/convert-function-declaration-to-arrow-function";
import convertIfElseToSwitch from "./refactorings/convert-if-else-to-switch";
import convertSwitchToIfElse from "./refactorings/convert-switch-to-if-else";
import convertIfElseToTernary from "./refactorings/convert-if-else-to-ternary";
@@ -57,6 +58,7 @@ export function activate(context: vscode.ExtensionContext) {
addBracesToIfStatement,
bubbleUpIfStatement,
convertForToForeach,
convertFunctionDeclarationToArrowFunction,
convertIfElseToSwitch,
convertSwitchToIfElse,
convertIfElseToTernary,
@@ -125,6 +127,7 @@ export function activate(context: vscode.ExtensionContext) {
addBracesToIfStatement,
bubbleUpIfStatement,
convertForToForeach,
convertFunctionDeclarationToArrowFunction,
convertIfElseToSwitch,
convertSwitchToIfElse,
convertIfElseToTernary,
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { Editor, ErrorReason, Code } from "../../editor/editor";
import { Selection } from "../../editor/selection";
import { InMemoryEditor } from "../../editor/adapters/in-memory-editor";
import { testEach } from "../../tests-helpers";

import { convertFunctionDeclarationToArrowFunction } from "./convert-function-declaration-to-arrow-function";

describe("Convert Function Declaration To Arrow Function", () => {
let showErrorMessage: Editor["showError"];

beforeEach(() => {
showErrorMessage = jest.fn();
});

testEach<{ code: Code; selection?: Selection; expected: Code }>(
"should convert function declaration to arrow function",
[
{
description: "non-generic",
code: `function fn(a: string): number { return 1; }`,
expected: `const fn = (a: string): number => { return 1; };`
},
{
description: "non-generic async",
code: `async function fn(a: string): number { return 1; }`,
expected: `const fn = async (a: string): number => { return 1; };`
},
{
description: "generic",
code: `function fn<T>(t: T): T { return t; }`,
expected: `const fn = <T>(t: T): T => { return t; };`
},
{
description: "generic async",
code: `async function fn<T>(t: T): T { return t; }`,
expected: `const fn = async <T>(t: T): T => { return t; };`
}
],
async ({ code, selection = Selection.cursorAt(0, 0), expected }) => {
const result = await doConvertFunctionDeclarationToArrowFunction(
code,
selection
);

expect(result).toBe(expected);
}
);

it("should show an error message if refactoring can't be made", async () => {
const code = `// This is a comment, can't be refactored`;
const selection = Selection.cursorAt(0, 0);

await doConvertFunctionDeclarationToArrowFunction(code, selection);

expect(showErrorMessage).toBeCalledWith(
ErrorReason.DidNotFindFunctionDeclarationToConvert
);
});

async function doConvertFunctionDeclarationToArrowFunction(
code: Code,
selection: Selection
): Promise<Code> {
const editor = new InMemoryEditor(code);
editor.showError = showErrorMessage;
await convertFunctionDeclarationToArrowFunction(code, selection, editor);
return editor.code;
}
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { Editor, Code, ErrorReason } from "../../editor/editor";
import { Selection } from "../../editor/selection";
import * as t from "../../ast";

export { convertFunctionDeclarationToArrowFunction, createVisitor };

async function convertFunctionDeclarationToArrowFunction(
code: Code,
selection: Selection,
editor: Editor
) {
const updatedCode = updateCode(t.parse(code), selection);

if (!updatedCode.hasCodeChanged) {
editor.showError(ErrorReason.DidNotFindFunctionDeclarationToConvert);
return;
}

await editor.write(updatedCode.code);
}

function updateCode(ast: t.AST, selection: Selection): t.Transformed {
return t.transformAST(
ast,
createVisitor(selection, path => {
const { node } = path;
const name = node.id ? node.id.name : "converted";
const identifier = t.identifier(name);

const arrowFunctionExpression = t.arrowFunctionExpression(
node.params,
node.body,
node.async
);
arrowFunctionExpression.returnType = node.returnType;
arrowFunctionExpression.typeParameters = node.typeParameters;

const declarator = t.variableDeclarator(
identifier,
arrowFunctionExpression
);

path.replaceWith(t.variableDeclaration("const", [declarator]));

path.stop();
})
);
}

function createVisitor(
selection: Selection,
onMatch: (path: t.NodePath<t.FunctionDeclaration>) => void
): t.Visitor {
return {
FunctionDeclaration(path) {
if (!selection.isInsidePath(path)) return;

onMatch(path);
}
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import {
convertFunctionDeclarationToArrowFunction,
createVisitor
} from "./convert-function-declaration-to-arrow-function";

import { RefactoringWithActionProvider } from "../../types";

const config: RefactoringWithActionProvider = {
command: {
key: "convertFunctionDeclarationToArrowFunction",
operation: convertFunctionDeclarationToArrowFunction,
title: "Convert Function Declaration To Arrow Function"
},
actionProvider: {
message: "Convert function declaration to arrow function",
createVisitor
}
};

export default config;

0 comments on commit 1ae228f

Please sign in to comment.