Merge pull request 'fix(status): banner Details strips Markdown syntax, not every #, _, >, * (#308)' (#390) from fix/kuma-plain-text into lotus
CI / Build & Quality Checks (push) Canceled after 0s
CI / Trigger Desktop Build (push) Canceled after 0s
CI / Secret scan (gitleaks) (push) Canceled after 0s
CI / Docker image build & smoke test (push) Canceled after 0s
CI / Playwright smoke (e2e) (push) Canceled after 0s

This commit was merged in pull request #390.
This commit is contained in:
2026-10-18 01:33:17 -04:00
2 changed files with 41 additions and 3 deletions
+25
View File
@@ -1,6 +1,7 @@
import { test } from 'node:test';
import assert from 'node:assert/strict';
import {
plain,
DEFAULT_GROUPS,
kumaBeatTime,
kumaUrls,
@@ -260,3 +261,27 @@ test('a dismissed calls-down banner lets the next one through, never hides serve
'server-down',
);
});
test('plain: strips Markdown syntax only, keeps ordinary #, _, > and * (#308)', () => {
assert.equal(
plain('join #lotus-general or #announcements:lotusguild.org'),
'join #lotus-general or #announcements:lotusguild.org',
);
assert.equal(
plain('ping @some_user about snake_case and C#'),
'ping @some_user about snake_case and C#',
);
assert.equal(
plain('calls -> fixed, > 5 people, 5 * 3 = 15'),
'calls -> fixed, > 5 people, 5 * 3 = 15',
);
assert.equal(
plain('# Heading\n* item one\n- item two\n> quoted'),
'Heading\nitem one\nitem two\nquoted',
);
assert.equal(plain('**bold**, *em*, _em_, `/sfu/get`'), 'bold, em, em, /sfu/get');
assert.equal(
plain('Read the <b>guide</b> <img src=x onerror=alert(1)> [docs](https://x.y)'),
'Read the guide docs',
);
});
+16 -3
View File
@@ -240,12 +240,25 @@ const incidentTone = (style: string): BannerTone => {
};
/** Markdown-ish incident text as plain text for the Details line. */
const plain = (s: string): string =>
/**
* [Gitea #308] Markdown → plain text for the Details line. Strips only the
* syntax: removing every `*_\`#>` also broke "#lotus-general", "snake_case",
* "->" and "5 * 3". HTML tags are dropped (React escapes the text anyway).
*/
export const plain = (s: string): string =>
s
.replace(/!\[[^\]]*\]\([^)]*\)/g, '')
.replace(/\[([^\]]+)\]\([^)]*\)/g, '$1')
.replace(/[*_`#>]/g, '')
.replace(/\s+\n/g, '\n')
.replace(/<\/?[a-z][^>]*>/gi, '')
.replace(/^[ \t]{0,3}#{1,6}[ \t]+/gm, '')
.replace(/^[ \t]*>[ \t]?/gm, '')
.replace(/^[ \t]*[*+-][ \t]+/gm, '')
.replace(/`([^`\n]+)`/g, '$1')
.replace(/\*\*(?=\S)([^*\n]*?\S)\*\*/g, '$1')
.replace(/__(?=\S)([^_\n]*?\S)__/g, '$1')
.replace(/(^|[^\w*])\*(?=\S)([^*\n]*?\S)\*(?![\w*])/g, '$1$2')
.replace(/(^|[^\w])_(?=\S)([^_\n]*?\S)_(?!\w)/g, '$1$2')
.replace(/[ \t]+\n/g, '\n')
.trim();
/**