From dac311e04aeee67a06cb97b99150c2f3af9d9a78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20H=C3=A9rault?= Date: Tue, 13 Dec 2022 15:10:59 +0100 Subject: [PATCH 1/4] Add #remove on JsxElement and JsxSelfClosingElement --- .../src/compiler/ast/jsx/JsxElement.ts | 22 +++++++++++-- .../compiler/ast/jsx/JsxSelfClosingElement.ts | 21 +++++++++++- .../tests/compiler/ast/jsx/jsxElementTests.ts | 32 ++++++++++++++++++- .../ast/jsx/jsxSelfClosingElementTests.ts | 32 ++++++++++++++++++- 4 files changed, 102 insertions(+), 5 deletions(-) diff --git a/packages/ts-morph/src/compiler/ast/jsx/JsxElement.ts b/packages/ts-morph/src/compiler/ast/jsx/JsxElement.ts index 6ffa8a3dc..6ab11d978 100644 --- a/packages/ts-morph/src/compiler/ast/jsx/JsxElement.ts +++ b/packages/ts-morph/src/compiler/ast/jsx/JsxElement.ts @@ -1,5 +1,5 @@ -import { errors, nameof, ts } from "@ts-morph/common"; -import { insertIntoParentTextRange } from "../../../manipulation"; +import { errors, nameof, SyntaxKind, ts } from "@ts-morph/common"; +import { FormattingKind, insertIntoParentTextRange, removeChildrenWithFormatting } from "../../../manipulation"; import { JsxElementSpecificStructure, JsxElementStructure, StructureKind } from "../../../structures"; import { WriterFunction } from "../../../types"; import { printTextFromStringOrWriter } from "../../../utils"; @@ -104,6 +104,24 @@ export class JsxElement extends JsxElementBase { delete structure.children; return structure; } + + /** + * Removes the JSX element. + */ + remove() { + removeChildrenWithFormatting({ + children: [this], + getSiblingFormatting: parent => { + const parentKind = parent.getKind() + + if (parentKind === SyntaxKind.JsxElement || parentKind === SyntaxKind.JsxOpeningElement) { + return FormattingKind.None + } + + throw new errors.InvalidOperationError(`Error removing JsxElement: parent is ${parent.getKindName()} and therefore the node cannot be removed. Only JsxElements with JsxElement parent can be removed`) + } + }); + } } function setText(element: JsxElement, newText: string) { diff --git a/packages/ts-morph/src/compiler/ast/jsx/JsxSelfClosingElement.ts b/packages/ts-morph/src/compiler/ast/jsx/JsxSelfClosingElement.ts index faf95b6ee..f299089f7 100644 --- a/packages/ts-morph/src/compiler/ast/jsx/JsxSelfClosingElement.ts +++ b/packages/ts-morph/src/compiler/ast/jsx/JsxSelfClosingElement.ts @@ -1,5 +1,6 @@ -import { ts } from "@ts-morph/common"; +import { errors, ts, SyntaxKind } from "@ts-morph/common"; import { JsxSelfClosingElementSpecificStructure, JsxSelfClosingElementStructure, StructureKind } from "../../../structures"; +import { FormattingKind, removeChildrenWithFormatting } from "../../../manipulation"; import { callBaseGetStructure } from "../callBaseGetStructure"; import { callBaseSet } from "../callBaseSet"; import { PrimaryExpression } from "../expression"; @@ -25,4 +26,22 @@ export class JsxSelfClosingElement extends JsxSelfClosingElementBase { + const parentKind = parent.getKind() + + if (parentKind === SyntaxKind.JsxElement || parentKind === SyntaxKind.JsxOpeningElement) { + return FormattingKind.None + } + + throw new errors.InvalidOperationError(`Error removing JsxSelfClosingElement: parent is ${parent.getKindName()} and therefore the node cannot be removed. Only JsxSelfClosingElements with JsxElement parent can be removed`) + } + }); + } } diff --git a/packages/ts-morph/src/tests/compiler/ast/jsx/jsxElementTests.ts b/packages/ts-morph/src/tests/compiler/ast/jsx/jsxElementTests.ts index 02adca8fd..31c1299b4 100644 --- a/packages/ts-morph/src/tests/compiler/ast/jsx/jsxElementTests.ts +++ b/packages/ts-morph/src/tests/compiler/ast/jsx/jsxElementTests.ts @@ -1,6 +1,6 @@ import { errors, nameof, SyntaxKind } from "@ts-morph/common"; import { expect } from "chai"; -import { JsxElement } from "../../../../compiler"; +import { JsxElement, JsxSelfClosingElement } from "../../../../compiler"; import { JsxAttributeStructure, JsxElementStructure, StructureKind } from "../../../../structures"; import { getInfoFromTextWithDescendant, OptionalKindAndTrivia, OptionalTrivia } from "../../testHelpers"; @@ -159,4 +159,34 @@ const v =
}); }); }); + + describe(nameof("remove"), () => { + function doRemove(text: string) { + const { descendant, sourceFile } = getInfo(text); + descendant.remove(); + } + + function doTestWithJsxElementChild(text: string, expected: string) { + const { descendant, sourceFile } = getInfo(text); + (descendant.getFirstDescendantByKind(SyntaxKind.JsxElement) as JsxElement).remove(); + expect(sourceFile.getFullText()).to.equal(expected); + } + + it("should not remove the root JsxElement", () => { + let error = null; + + try { + doRemove(`var t = ();`); + } + catch (err) { + error = err; + } + + expect(error).to.be.instanceOf(errors.InvalidOperationError); + }); + + it("should remove the JsxElement child", () => { + doTestWithJsxElementChild(`var t = ();`, `var t = ();`); + }); + }); }); diff --git a/packages/ts-morph/src/tests/compiler/ast/jsx/jsxSelfClosingElementTests.ts b/packages/ts-morph/src/tests/compiler/ast/jsx/jsxSelfClosingElementTests.ts index 43130cca9..bc6ea15f9 100644 --- a/packages/ts-morph/src/tests/compiler/ast/jsx/jsxSelfClosingElementTests.ts +++ b/packages/ts-morph/src/tests/compiler/ast/jsx/jsxSelfClosingElementTests.ts @@ -1,4 +1,4 @@ -import { nameof, SyntaxKind } from "@ts-morph/common"; +import { errors, nameof, SyntaxKind } from "@ts-morph/common"; import { expect } from "chai"; import { JsxSelfClosingElement } from "../../../../compiler"; import { JsxAttributeStructure, JsxSelfClosingElementStructure, StructureKind } from "../../../../structures"; @@ -167,4 +167,34 @@ describe("JsxSelfClosingElement", () => { expect(descendant.getFullText()).to.equal(``); }); }); + + describe(nameof("remove"), () => { + function doRemove(text: string) { + const { descendant, sourceFile } = getInfo(text); + descendant.remove(); + } + + function doTestWithJsxSelfClosingElementChild(text: string, expected: string) { + const { descendant, sourceFile } = getInfo(text); + descendant.remove(); + expect(sourceFile.getFullText()).to.equal(expected); + } + + it("should not remove the root JsxSelfClosingElement", () => { + let error = null; + + try { + doRemove(`var t = ();`); + } + catch (err) { + error = err; + } + + expect(error).to.be.instanceOf(errors.InvalidOperationError); + }); + + it("should remove the JsxSelfClosingElement child", () => { + doTestWithJsxSelfClosingElementChild(`var t = ();`, `var t = ();`); + }); + }); }); From 9635d0d4f3f37326d53c24504eb691accbc8fbe5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20H=C3=A9rault?= Date: Tue, 13 Dec 2022 15:16:30 +0100 Subject: [PATCH 2/4] Improve #remove --- .../src/compiler/ast/jsx/JsxElement.ts | 19 ++++++++----------- .../compiler/ast/jsx/JsxSelfClosingElement.ts | 19 ++++++++----------- 2 files changed, 16 insertions(+), 22 deletions(-) diff --git a/packages/ts-morph/src/compiler/ast/jsx/JsxElement.ts b/packages/ts-morph/src/compiler/ast/jsx/JsxElement.ts index 6ab11d978..1e7aae303 100644 --- a/packages/ts-morph/src/compiler/ast/jsx/JsxElement.ts +++ b/packages/ts-morph/src/compiler/ast/jsx/JsxElement.ts @@ -1,5 +1,5 @@ import { errors, nameof, SyntaxKind, ts } from "@ts-morph/common"; -import { FormattingKind, insertIntoParentTextRange, removeChildrenWithFormatting } from "../../../manipulation"; +import { insertIntoParentTextRange, removeChildren } from "../../../manipulation"; import { JsxElementSpecificStructure, JsxElementStructure, StructureKind } from "../../../structures"; import { WriterFunction } from "../../../types"; import { printTextFromStringOrWriter } from "../../../utils"; @@ -109,18 +109,15 @@ export class JsxElement extends JsxElementBase { * Removes the JSX element. */ remove() { - removeChildrenWithFormatting({ - children: [this], - getSiblingFormatting: parent => { - const parentKind = parent.getKind() + const parentKind = this.getParent()?.getKind() - if (parentKind === SyntaxKind.JsxElement || parentKind === SyntaxKind.JsxOpeningElement) { - return FormattingKind.None - } + if (!(parentKind === SyntaxKind.JsxElement || parentKind === SyntaxKind.JsxOpeningElement)) { + throw new errors.InvalidOperationError(`Error removing JsxElement: parent is ${this.getParent()?.getKindName() ?? '(no parent)'} and therefore the node cannot be removed. Only JsxElements with JsxElement parent can be removed`) + } - throw new errors.InvalidOperationError(`Error removing JsxElement: parent is ${parent.getKindName()} and therefore the node cannot be removed. Only JsxElements with JsxElement parent can be removed`) - } - }); + return removeChildren({ + children: [this], + }) } } diff --git a/packages/ts-morph/src/compiler/ast/jsx/JsxSelfClosingElement.ts b/packages/ts-morph/src/compiler/ast/jsx/JsxSelfClosingElement.ts index f299089f7..b57954270 100644 --- a/packages/ts-morph/src/compiler/ast/jsx/JsxSelfClosingElement.ts +++ b/packages/ts-morph/src/compiler/ast/jsx/JsxSelfClosingElement.ts @@ -1,6 +1,6 @@ import { errors, ts, SyntaxKind } from "@ts-morph/common"; import { JsxSelfClosingElementSpecificStructure, JsxSelfClosingElementStructure, StructureKind } from "../../../structures"; -import { FormattingKind, removeChildrenWithFormatting } from "../../../manipulation"; +import { removeChildren } from "../../../manipulation"; import { callBaseGetStructure } from "../callBaseGetStructure"; import { callBaseSet } from "../callBaseSet"; import { PrimaryExpression } from "../expression"; @@ -31,17 +31,14 @@ export class JsxSelfClosingElement extends JsxSelfClosingElementBase { - const parentKind = parent.getKind() + const parentKind = this.getParent()?.getKind() - if (parentKind === SyntaxKind.JsxElement || parentKind === SyntaxKind.JsxOpeningElement) { - return FormattingKind.None - } + if (!(parentKind === SyntaxKind.JsxElement || parentKind === SyntaxKind.JsxOpeningElement)) { + throw new errors.InvalidOperationError(`Error removing JsxElement: parent is ${this.getParent()?.getKindName() ?? '(no parent)'} and therefore the node cannot be removed. Only JsxElements with JsxElement parent can be removed`) + } - throw new errors.InvalidOperationError(`Error removing JsxSelfClosingElement: parent is ${parent.getKindName()} and therefore the node cannot be removed. Only JsxSelfClosingElements with JsxElement parent can be removed`) - } - }); + return removeChildren({ + children: [this], + }) } } From d6bd97d7bbfcccc45d8cf28876e474cb3d840141 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20H=C3=A9rault?= Date: Tue, 13 Dec 2022 15:36:02 +0100 Subject: [PATCH 3/4] Improve error message --- packages/ts-morph/src/compiler/ast/jsx/JsxSelfClosingElement.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ts-morph/src/compiler/ast/jsx/JsxSelfClosingElement.ts b/packages/ts-morph/src/compiler/ast/jsx/JsxSelfClosingElement.ts index b57954270..e24350246 100644 --- a/packages/ts-morph/src/compiler/ast/jsx/JsxSelfClosingElement.ts +++ b/packages/ts-morph/src/compiler/ast/jsx/JsxSelfClosingElement.ts @@ -34,7 +34,7 @@ export class JsxSelfClosingElement extends JsxSelfClosingElementBase Date: Tue, 13 Dec 2022 16:49:26 +0100 Subject: [PATCH 4/4] Include JsxFragment --- packages/ts-morph/src/compiler/ast/jsx/JsxElement.ts | 4 ++-- .../ts-morph/src/compiler/ast/jsx/JsxSelfClosingElement.ts | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/ts-morph/src/compiler/ast/jsx/JsxElement.ts b/packages/ts-morph/src/compiler/ast/jsx/JsxElement.ts index 1e7aae303..977b81c00 100644 --- a/packages/ts-morph/src/compiler/ast/jsx/JsxElement.ts +++ b/packages/ts-morph/src/compiler/ast/jsx/JsxElement.ts @@ -111,8 +111,8 @@ export class JsxElement extends JsxElementBase { remove() { const parentKind = this.getParent()?.getKind() - if (!(parentKind === SyntaxKind.JsxElement || parentKind === SyntaxKind.JsxOpeningElement)) { - throw new errors.InvalidOperationError(`Error removing JsxElement: parent is ${this.getParent()?.getKindName() ?? '(no parent)'} and therefore the node cannot be removed. Only JsxElements with JsxElement parent can be removed`) + if (!(parentKind === SyntaxKind.JsxElement || parentKind === SyntaxKind.JsxOpeningElement || parentKind === SyntaxKind.JsxFragment)) { + throw new errors.InvalidOperationError(`Error removing JsxElement: parent is ${this.getParent()?.getKindName() ?? '(no parent)'} and therefore the node cannot be removed. Only JsxElements with JsxElement/JsxOpeningElement/JsxFragment parent can be removed`) } return removeChildren({ diff --git a/packages/ts-morph/src/compiler/ast/jsx/JsxSelfClosingElement.ts b/packages/ts-morph/src/compiler/ast/jsx/JsxSelfClosingElement.ts index e24350246..35677b5f2 100644 --- a/packages/ts-morph/src/compiler/ast/jsx/JsxSelfClosingElement.ts +++ b/packages/ts-morph/src/compiler/ast/jsx/JsxSelfClosingElement.ts @@ -30,11 +30,11 @@ export class JsxSelfClosingElement extends JsxSelfClosingElementBase