diff --git a/__tests__/index.spec.tsx b/__tests__/index.spec.tsx index c7aef42..9120e54 100644 --- a/__tests__/index.spec.tsx +++ b/__tests__/index.spec.tsx @@ -1,12 +1,14 @@ import { shallow } from "enzyme"; import React from "react"; +import Anser from "anser"; import Ansi from "../src/index"; const GREEN_FG = "\u001b[32m"; const YELLOW_BG = "\u001b[43m"; const BOLD = "\u001b[1m"; const RESET = "\u001b[0;m"; +const NO_OP = "\u001b[99m"; describe("Ansi", () => { test("hello world", () => { @@ -269,4 +271,83 @@ describe("Ansi", () => { ); }); }); + + describe("as span", () => { + test("can return hello world as a span element", () => { + const el = shallow( + React.createElement(Ansi, { as: "span" }, "hello world") + ); + expect(el).not.toBeNull(); + expect(el.text()).toBe("hello world"); + expect(el.html()).toBe( + 'hello world' + ); + }); + + test("can return a link as a span element", () => { + const el = shallow( + React.createElement(Ansi, { as: "span", linkify: true }, "https://nteract.io/") + ); + expect(el).not.toBeNull(); + expect(el.text()).toBe("https://nteract.io/"); + expect(el.html()).toBe( + 'https://nteract.io/' + ); + }); + + test("can return nested span elements with color", () => { + const el = shallow( + React.createElement(Ansi, { as: "span" }, `${GREEN_FG}hello ${YELLOW_BG}world`) + ); + expect(el).not.toBeNull(); + expect(el.text()).toBe("hello world"); + expect(el.html()).toBe( + 'hello world' + ); + }); + }); + + describe("data in chunks", () => { + describe("without anser prop", () => { + test("doesn't carry colors over", () => { + const dataInChunks = [`${GREEN_FG}hello `, `${YELLOW_BG}world`]; + let el = ""; + dataInChunks.map((spandata) => + el += (shallow(React.createElement(Ansi, { as: "span" }, spandata)).html()) + ); + expect(el).not.toBeNull(); + expect(el).toBe( + 'hello world' + ); + }); + }); + + describe("with anser prop", () => { + test("can carry colors over", () => { + const anser = new Anser(); + const dataInChunks = [`${GREEN_FG}hello `, `${YELLOW_BG}world`]; + let el = ""; + dataInChunks.map((spandata) => + el += (shallow(React.createElement(Ansi, { as: "span", anser: anser }, spandata)).html()) + ); + expect(el).not.toBeNull(); + expect(el).toBe( + 'hello world' + ); + }); + + test("can carry colors over using a no-op option for chunks without code", () => { + const anser = new Anser(); + const dataInChunks = [`${GREEN_FG}hello `, `${NO_OP}world`]; + let el = ""; + dataInChunks.map((spandata) => + el += (shallow(React.createElement(Ansi, { as: "span", anser: anser }, spandata)).html()) + ); + expect(el).not.toBeNull(); + expect(el).toBe( + 'hello world' + ); + }); + }); + }); }); diff --git a/src/index.ts b/src/index.ts index 888670a..7b1bfe7 100644 --- a/src/index.ts +++ b/src/index.ts @@ -13,10 +13,11 @@ import * as React from "react"; */ function ansiToJSON( input: string, - use_classes: boolean = false + use_classes: boolean = false, + anser: Anser ): AnserJsonEntry[] { input = escapeCarriageReturn(input); - return Anser.ansiToJson(input, { + return anser.ansiToJson(input, { json: true, remove_empty: true, use_classes @@ -143,14 +144,18 @@ declare interface Props { linkify?: boolean; className?: string; useClasses?: boolean; + as?: string; + anser?: Anser; } export default function Ansi(props: Props): JSX.Element { - const { className, useClasses, children, linkify } = props; + const { className, useClasses, children, linkify, as, anser } = props; + const elementType = ( as === "span" ) ? React.Fragment : "code"; + const elementProps = ( as === "span" ) ? null : { className }; return React.createElement( - "code", - { className }, - ansiToJSON(children ?? "", useClasses ?? false).map( + elementType, + elementProps, + ansiToJSON(children ?? "", useClasses ?? false, anser ?? new Anser()).map( convertBundleIntoReact.bind(null, linkify ?? false, useClasses ?? false) ) );