Skip to content

Commit

Permalink
feat: Add JsxElement setBodyText and setBodyTextInline.
Browse files Browse the repository at this point in the history
  • Loading branch information
dsherret committed Feb 28, 2018
1 parent 76f9531 commit 1420786
Show file tree
Hide file tree
Showing 2 changed files with 103 additions and 0 deletions.
55 changes: 55 additions & 0 deletions src/compiler/jsx/JsxElement.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import CodeBlockWriter from "code-block-writer";
import {ts} from "./../../typescript";
import {insertIntoParentTextRange} from "./../../manipulation";
import {getTextFromStringOrWriter, writeTextFromStringOrWriter} from "./../../utils";
import {getBodyText} from "./../base/helpers";
import {PrimaryExpression} from "./../expression";
import {JsxChild} from "./../aliases";
import {JsxOpeningElement} from "./JsxOpeningElement";
Expand All @@ -25,4 +29,55 @@ export class JsxElement extends PrimaryExpression<ts.JsxElement> {
getClosingElement() {
return this.getNodeFromCompilerNode<JsxClosingElement>(this.compilerNode.closingElement);
}

/**
* Sets the body text.
* @param writerFunction - Write the text using the provided writer.
*/
setBodyText(writerFunction: (writer: CodeBlockWriter) => void): this;
/**
* Sets the body text.
* @param text - Text to set as the body.
*/
setBodyText(text: string): this;
setBodyText(textOrWriterFunction: string | ((writer: CodeBlockWriter) => void)) {
const newText = getBodyText(this.getWriterWithIndentation(), textOrWriterFunction);
setText(this, newText);
return this;
}

/**
* Sets the body text without surrounding new lines.
* @param writerFunction - Write the text using the provided writer.
*/
setBodyTextInline(writerFunction: (writer: CodeBlockWriter) => void): this;
/**
* Sets the body text without surrounding new lines.
* @param text - Text to set as the body.
*/
setBodyTextInline(text: string): this;
setBodyTextInline(textOrWriterFunction: string | ((writer: CodeBlockWriter) => void)) {
const writer = this.getWriterWithQueuedChildIndentation();
writeTextFromStringOrWriter(writer, textOrWriterFunction);
if (writer.isLastNewLine()) {
writer.setIndentationLevel(Math.max(0, this.getIndentationLevel() - 1));
writer.write(""); // indentation
}
setText(this, writer.toString());
return this;
}
}

function setText(element: JsxElement, newText: string) {
const openingElement = element.getOpeningElement();
const closingElement = element.getClosingElement();

insertIntoParentTextRange({
insertPos: openingElement.getEnd(),
newText,
parent: element.getChildSyntaxListOrThrow(),
replacing: {
textLength: closingElement.getStart() - openingElement.getEnd()
}
});
}
48 changes: 48 additions & 0 deletions src/tests/compiler/jsx/jsxElementTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,52 @@ describe(nameof(JsxElement), () => {
doTest(`var t = (<jsx>\n <Child1 />\n <Child2 />\n</jsx>);`, ["", "<Child1 />", "", "<Child2 />", ""]);
});
});

describe(nameof<JsxElement>(n => n.setBodyText), () => {
function doTest(text: string, bodyText: string, expected: string) {
const {descendant, sourceFile} = getInfo(text);
descendant.setBodyText(bodyText);
expect(sourceFile.getFullText()).to.equal(expected);
}

it("should set the body text", () => {
doTest("var t = (<jsx></jsx>);", "<element />", "var t = (<jsx>\n <element />\n</jsx>);");
});

it("should set the body text when currently on multiple lines", () => {
doTest("var t = (\n <jsx>\n </jsx>);", "<element />", "var t = (\n <jsx>\n <element />\n </jsx>);");
});

it("should set the body text when specifying multiple lines", () => {
doTest("var t = (<jsx></jsx>);", "<element>\n</element>", "var t = (<jsx>\n <element>\n </element>\n</jsx>);");
});

it("should set the body text when specifying multiple lines and other elements exist", () => {
doTest("var t = (<jsx> <Element> </Element> </jsx>);", "<element>\n</element>", "var t = (<jsx>\n <element>\n </element>\n</jsx>);");
});
});

describe(nameof<JsxElement>(n => n.setBodyTextInline), () => {
function doTest(text: string, bodyText: string, expected: string) {
const {descendant, sourceFile} = getInfo(text);
descendant.setBodyTextInline(bodyText);
expect(sourceFile.getFullText()).to.equal(expected);
}

it("should set the body text inline", () => {
doTest("var t = (<jsx></jsx>);", "<element />", "var t = (<jsx><element /></jsx>);");
});

it("should set the body text inline when other elements exist", () => {
doTest("var t = (<jsx><element2 /></jsx>);", "<element />", "var t = (<jsx><element /></jsx>);");
});

it("should indent if writing a new line", () => {
doTest("var t = (<jsx></jsx>);", "<element>\n</element>", "var t = (<jsx><element>\n </element></jsx>);");
});

it("should indent if ending with a new line", () => {
doTest("var t = (<jsx></jsx>);", "<element>\n</element>\n", "var t = (<jsx><element>\n </element>\n</jsx>);");
});
});
});

0 comments on commit 1420786

Please sign in to comment.