Skip to content

Commit

Permalink
feat: Add JsxAttribute .setInitializer & .removeInitializer
Browse files Browse the repository at this point in the history
  • Loading branch information
dsherret committed Sep 22, 2018
1 parent 0c6fcf0 commit 9436954
Show file tree
Hide file tree
Showing 3 changed files with 91 additions and 3 deletions.
2 changes: 1 addition & 1 deletion src/compiler/common/Node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1148,7 +1148,7 @@ export class Node<NodeType extends ts.Node = ts.Node> {
/** @internal */
replaceWithText(textOrWriterFunction: string | WriterFunction, writer: CodeBlockWriter): Node;
replaceWithText(textOrWriterFunction: string | WriterFunction, writer?: CodeBlockWriter): Node {
const newText = getTextFromStringOrWriter(writer || this.getWriter(), textOrWriterFunction);
const newText = getTextFromStringOrWriter(writer || this.getWriterWithQueuedIndentation(), textOrWriterFunction);
if (TypeGuards.isSourceFile(this)) {
this.replaceText([this.getPos(), this.getEnd()], newText);
return this;
Expand Down
51 changes: 49 additions & 2 deletions src/compiler/jsx/JsxAttribute.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import * as errors from "../../errors";
import { removeChildren } from "../../manipulation";
import { removeChildren, insertIntoParentTextRange } from "../../manipulation";
import { JsxAttributeStructure, JsxAttributeStructureSpecific } from "../../structures";
import { ts } from "../../typescript";
import { ts, SyntaxKind } from "../../typescript";
import { WriterFunction } from "../../types";
import { StringUtils, getTextFromStringOrWriter } from "../../utils";
import { NamedNode } from "../base";
import { Node } from "../common";
import { callBaseGetStructure } from "../callBaseGetStructure";
Expand All @@ -24,6 +26,51 @@ export class JsxAttribute extends JsxAttributeBase<ts.JsxAttribute> {
return this.getNodeFromCompilerNodeIfExists(this.compilerNode.initializer);
}

/**
* Sets the initializer.
* @param textOrWriterFunction - Text or writer function to set the initializer with.
* @remarks You need to provide the quotes or braces.
*/
setInitializer(textOrWriterFunction: string | WriterFunction) {
const text = getTextFromStringOrWriter(this.getWriterWithQueuedIndentation(), textOrWriterFunction);

if (StringUtils.isNullOrWhitespace(text)) {
this.removeInitializer();
return this;
}

const initializer = this.getInitializer();
if (initializer != null) {
initializer.replaceWithText(text);
return this;
}

insertIntoParentTextRange({
insertPos: this.getNameNode().getEnd(),
parent: this,
newText: `=${text}`
});

return this;
}

/**
* Removes the initializer.
*/
removeInitializer() {
const initializer = this.getInitializer();
if (initializer == null)
return this;

removeChildren({
children: [initializer.getPreviousSiblingIfKindOrThrow(SyntaxKind.EqualsToken), initializer],
removePrecedingSpaces: true,
removePrecedingNewLines: true
});

return this;
}

/**
* Removes the JSX attribute.
*/
Expand Down
41 changes: 41 additions & 0 deletions src/tests/compiler/jsx/jsxAttributeTests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { expect } from "chai";
import { JsxAttribute, JsxSelfClosingElement } from "../../../compiler";
import { JsxAttributeStructure } from "../../../structures";
import { SyntaxKind } from "../../../typescript";
import { WriterFunction } from "../../../types";
import { getInfoFromTextWithDescendant } from "../testHelpers";

function getInfo(text: string) {
Expand Down Expand Up @@ -79,6 +80,46 @@ describe(nameof(JsxAttribute), () => {
});
});

describe(nameof<JsxAttribute>(n => n.setInitializer), () => {
function doTest(text: string, initializerText: string | WriterFunction, expected: string) {
const { descendant, sourceFile } = getInfoForSelfClosingElement(text);
(descendant.getAttributes()[0] as JsxAttribute).setInitializer(initializerText);
expect(sourceFile.getFullText()).to.equal(expected);
}

it("should set when one doesn't exist", () => {
doTest(`var t = (<jsx attribute />);`, writer => writer.quote("5"), `var t = (<jsx attribute="5" />);`);
});

it("should set when is a quote", () => {
doTest(`var t = (<jsx attribute="5" />);`, "{6}", `var t = (<jsx attribute={6} />);`);
});

it("should remove when empty", () => {
doTest(`var t = (<jsx attribute="5" />);`, "", `var t = (<jsx attribute />);`);
});
});

describe(nameof<JsxAttribute>(n => n.removeInitializer), () => {
function doTest(text: string, expected: string) {
const { descendant, sourceFile } = getInfoForSelfClosingElement(text);
(descendant.getAttributes()[0] as JsxAttribute).removeInitializer();
expect(sourceFile.getFullText()).to.equal(expected);
}

it("should remove the initializer when it is a string", () => {
doTest(`var t = (<jsx attribute="4" />);`, `var t = (<jsx attribute />);`);
});

it("should remove the initializer when it is an expression", () => {
doTest(`var t = (<jsx attribute={5} />);`, `var t = (<jsx attribute />);`);
});

it("should do nothing when it doesn't exist", () => {
doTest(`var t = (<jsx attribute />);`, `var t = (<jsx attribute />);`);
});
});

describe(nameof<JsxAttribute>(n => n.remove), () => {
function doTest(text: string, index: number, expected: string) {
const {descendant, sourceFile} = getInfoForSelfClosingElement(text);
Expand Down

0 comments on commit 9436954

Please sign in to comment.