diff --git a/CHANGELOG.md b/CHANGELOG.md index 80bd6c78..8cd80736 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] ### Changed - Add directory hierarchy awareness to document sorting ([#517](https://github.com/cucumber/react-components/pull/517)) by [@MuhammadTalha57](https://github.com/MuhammadTalha57) +- Replace ANSI handling library ([#562](https://github.com/cucumber/react-components/pull/562)) ## [24.3.0] - 2026-04-13 ### Added diff --git a/package-lock.json b/package-lock.json index 33926f3f..a1fd36a8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,7 +19,7 @@ "@orama/orama": "^3.0.0", "@orama/stemmers": "^3.0.0", "@teppeis/multimaps": "3.0.0", - "ansi-to-html": "0.7.2", + "ansi_up": "6.0.6", "date-fns": "4.4.0", "hast-util-sanitize": "^5.0.1", "highlight-words-core": "1.2.3", @@ -511,9 +511,6 @@ "arm64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT OR Apache-2.0", "optional": true, "os": [ @@ -531,9 +528,6 @@ "arm64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT OR Apache-2.0", "optional": true, "os": [ @@ -551,9 +545,6 @@ "x64" ], "dev": true, - "libc": [ - "glibc" - ], "license": "MIT OR Apache-2.0", "optional": true, "os": [ @@ -571,9 +562,6 @@ "x64" ], "dev": true, - "libc": [ - "musl" - ], "license": "MIT OR Apache-2.0", "optional": true, "os": [ @@ -3971,6 +3959,15 @@ "node": ">=8" } }, + "node_modules/ansi_up": { + "version": "6.0.6", + "resolved": "https://registry.npmjs.org/ansi_up/-/ansi_up-6.0.6.tgz", + "integrity": "sha512-yIa1x3Ecf8jWP4UWEunNjqNX6gzE4vg2gGz+xqRGY+TBSucnYp6RRdPV4brmtg6bQ1ljD48mZ5iGSEj7QEpRKA==", + "license": "MIT", + "engines": { + "node": "*" + } + }, "node_modules/ansi-align": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz", @@ -4032,20 +4029,6 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/ansi-to-html": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/ansi-to-html/-/ansi-to-html-0.7.2.tgz", - "integrity": "sha512-v6MqmEpNlxF+POuyhKkidusCHWWkaLcGRURzivcU3I9tv7k4JVhFcnukrM5Rlk2rUywdZuzYAZ+kbZqWCnfN3g==", - "dependencies": { - "entities": "^2.2.0" - }, - "bin": { - "ansi-to-html": "bin/ansi-to-html" - }, - "engines": { - "node": ">=8.0.0" - } - }, "node_modules/append-transform": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/append-transform/-/append-transform-2.0.0.tgz", @@ -5213,14 +5196,6 @@ "node": ">= 0.8" } }, - "node_modules/entities": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, "node_modules/es-define-property": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", @@ -12257,6 +12232,22 @@ } } }, + "node_modules/vite-tsconfig-paths/node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, "node_modules/vite/node_modules/fdir": { "version": "6.4.4", "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.4.tgz", diff --git a/package.json b/package.json index 82eb512d..729e54e8 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "@orama/orama": "^3.0.0", "@orama/stemmers": "^3.0.0", "@teppeis/multimaps": "3.0.0", - "ansi-to-html": "0.7.2", + "ansi_up": "6.0.6", "date-fns": "4.4.0", "hast-util-sanitize": "^5.0.1", "highlight-words-core": "1.2.3", diff --git a/src/components/gherkin/attachment/Attachment.spec.tsx b/src/components/gherkin/attachment/Attachment.spec.tsx index 0c969dc2..77dce130 100644 --- a/src/components/gherkin/attachment/Attachment.spec.tsx +++ b/src/components/gherkin/attachment/Attachment.spec.tsx @@ -315,7 +315,7 @@ describe('', () => { const { container } = render() const data = container.querySelector('pre > span') expect(data).to.contain.html( - 'blackwhite' + 'blackwhite' ) expect(screen.getByRole('button', { name: 'Copy' })).to.be.visible }) @@ -330,10 +330,22 @@ describe('', () => { const { container } = render() const data = container.querySelector('pre > span') expect(data).to.contain.html( - 'blackwhite' + 'blackwhite' ) }) + it('escapes HTML in the log content', () => { + const attachment: AttachmentMessage = { + mediaType: 'text/x.cucumber.log+plain', + body: '', + contentEncoding: AttachmentContentEncoding.IDENTITY, + } + const { container } = render() + const data = container.querySelector('pre > span') + expect(data?.querySelector('img')).to.equal(null) + expect(data).to.have.text('') + }) + it('copies raw content without ANSI conversion when clicking copy button', async () => { const attachment: AttachmentMessage = { mediaType: 'text/x.cucumber.log+plain', diff --git a/src/components/gherkin/attachment/Log.tsx b/src/components/gherkin/attachment/Log.tsx index 7a0e084a..b7dd6b59 100644 --- a/src/components/gherkin/attachment/Log.tsx +++ b/src/components/gherkin/attachment/Log.tsx @@ -1,7 +1,7 @@ // biome-ignore-all lint/security/noDangerouslySetInnerHtml: pre-sanitised import type { Attachment } from '@cucumber/messages' -import Convert from 'ansi-to-html' +import { AnsiUp } from 'ansi_up' import type { FC } from 'react' import { CopyButton } from '../../app/CopyButton.js' @@ -24,5 +24,5 @@ export const Log: FC<{ } function prettyANSI(s: string) { - return new Convert().toHtml(s) + return new AnsiUp().ansi_to_html(s) }