Skip to content

Commit 10ffb15

Browse files
chore(deps): Replace showdown dependency with marked (#369)
1 parent 59d951c commit 10ffb15

File tree

6 files changed

+63
-35
lines changed

6 files changed

+63
-35
lines changed

packages/dev/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
"react-dom": "^18.2.0",
2323
"react-i18next": "^11.7.3",
2424
"react-router-dom": "^6.11.2",
25-
"showdown": "2.1.0",
25+
"marked": "^15.0.6",
2626
"lodash-es": "^4.17.21"
2727
},
2828
"devDependencies": {

packages/module/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
"@patternfly/react-core": ">=5.0.0",
4848
"react": ">=16.8.0",
4949
"react-dom": ">=16.8.0",
50-
"showdown": ">=2.1.0"
50+
"marked": "^15.0.6"
5151
},
5252
"dependencies": {
5353
"@patternfly/react-catalog-view-extension": "^5.0.0",

packages/module/src/ConsoleInternal/components/markdown-view.tsx

Lines changed: 34 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import * as React from 'react';
22
import { css } from '@patternfly/react-styles';
3-
import { Converter } from 'showdown';
3+
import { marked } from 'marked';
44
import { useForceRender } from '@console/shared';
55
import { QuickStartContext, QuickStartContextValues } from '../../utils/quick-start-context';
66
import './_markdown-view.scss';
@@ -16,18 +16,7 @@ interface ShowdownExtension {
1616
replace?: (...args: any[]) => string;
1717
}
1818

19-
export const markdownConvert = (markdown, extensions?: ShowdownExtension[]) => {
20-
const converter = new Converter({
21-
tables: true,
22-
openLinksInNewWindow: true,
23-
strikethrough: true,
24-
emoji: false,
25-
});
26-
27-
if (extensions) {
28-
converter.addExtension(extensions);
29-
}
30-
19+
export const markdownConvert = async (markdown: string, extensions?: ShowdownExtension[]) => {
3120
DOMPurify.addHook('beforeSanitizeElements', function (node) {
3221
// nodeType 1 = element type
3322

@@ -62,12 +51,26 @@ export const markdownConvert = (markdown, extensions?: ShowdownExtension[]) => {
6251
}
6352
});
6453

65-
return DOMPurify.sanitize(converter.makeHtml(markdown), {
66-
USE_PROFILES: {
67-
html: true,
68-
svg: true,
69-
},
70-
});
54+
// Replace code fences with non markdown formatting relates tokens so that marked doesn't try to parse them as code spans
55+
const markdownWithSubstitutedCodeFences = markdown.replace(/```/g, '@@@');
56+
const parsedMarkdown = await marked.parse(markdownWithSubstitutedCodeFences);
57+
// Swap the temporary tokens back to code fences before we run the extensions
58+
let md = parsedMarkdown.replace(/@@@/g, '```');
59+
60+
if (extensions) {
61+
// Convert code spans back to md format before we run the custom extension regexes
62+
md = md.replace(/<code>(.*)<\/code>/g, '`$1`');
63+
64+
extensions.forEach(({ regex, replace }) => {
65+
if (regex) {
66+
md = md.replace(regex, replace);
67+
}
68+
});
69+
70+
// Convert any remaining backticks back into code spans
71+
md = md.replace(/`(.*)`/g, '<code>$1</code>');
72+
}
73+
return DOMPurify.sanitize(md);
7174
};
7275

7376
interface SyncMarkdownProps {
@@ -96,10 +99,18 @@ export const SyncMarkdownView: React.FC<SyncMarkdownProps> = ({
9699
className,
97100
}) => {
98101
const { getResource } = React.useContext<QuickStartContextValues>(QuickStartContext);
99-
const markup = React.useMemo(
100-
() => markdownConvert(content || emptyMsg || getResource('Not available'), extensions),
101-
[content, emptyMsg, extensions, getResource],
102-
);
102+
const [markup, setMarkup] = React.useState<string>('');
103+
104+
React.useEffect(() => {
105+
async function getMd() {
106+
const md = await markdownConvert(
107+
content || emptyMsg || getResource('Not available'),
108+
extensions,
109+
);
110+
setMarkup(md);
111+
}
112+
getMd();
113+
}, [content, emptyMsg, getResource, extensions]);
103114
const innerProps: InnerSyncMarkdownProps = {
104115
renderExtension: extensions?.length > 0 ? renderExtension : undefined,
105116
exactHeight,

packages/module/src/QuickStartPanelContent.tsx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ const QuickStartPanelContent: React.FC<QuickStartPanelContentProps> = ({
5959
const { getResource, activeQuickStartState, focusOnQuickStart } =
6060
React.useContext<QuickStartContextValues>(QuickStartContext);
6161
const [contentRef, setContentRef] = React.useState<HTMLDivElement>();
62+
const [displayName, setDisplayName] = React.useState<string>('');
6263
const shadows = useScrollShadows(contentRef);
6364
const quickStart = quickStarts.find((qs) => qs.metadata.name === activeQuickStartID);
6465
const taskNumber = activeQuickStartState?.taskNumber;
@@ -95,6 +96,14 @@ const QuickStartPanelContent: React.FC<QuickStartPanelContentProps> = ({
9596
}
9697
}, [focusOnQuickStart, quickStart]);
9798

99+
React.useEffect(() => {
100+
async function getDisplayName() {
101+
const convertedMdDisplayName = await markdownConvert(quickStart?.spec.displayName);
102+
setDisplayName(removeParagraphWrap(convertedMdDisplayName));
103+
}
104+
getDisplayName();
105+
}, [quickStart]);
106+
98107
const content = quickStart ? (
99108
<DrawerPanelContent
100109
isResizable={isResizable}
@@ -115,7 +124,7 @@ const QuickStartPanelContent: React.FC<QuickStartPanelContentProps> = ({
115124
>
116125
<span
117126
dangerouslySetInnerHTML={{
118-
__html: removeParagraphWrap(markdownConvert(quickStart?.spec.displayName)),
127+
__html: displayName,
119128
}}
120129
/>{' '}
121130
<small className="pfext-quick-start-panel-content__duration">

packages/module/src/controller/QuickStartTaskHeader.tsx

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,13 +67,23 @@ const QuickStartTaskHeader: React.FC<QuickStartTaskHeaderProps> = ({
6767
}) => {
6868
const titleRef = React.useRef(null);
6969
const { focusOnQuickStart } = React.useContext(QuickStartContext);
70+
const [parsedTitle, setParsedTitle] = React.useState<string>('');
7071

7172
React.useEffect(() => {
7273
if (focusOnQuickStart && isActiveTask) {
7374
// Focus the WizardNavItem button element that contains the title
7475
titleRef.current.parentNode.focus();
7576
}
7677
}, [focusOnQuickStart, isActiveTask]);
78+
79+
React.useEffect(() => {
80+
async function getParsedTitle() {
81+
const convertedMdTitle = await markdownConvert(title);
82+
setParsedTitle(removeParagraphWrap(convertedMdTitle));
83+
}
84+
getParsedTitle();
85+
}, [title]);
86+
7787
const classNames = css('pfext-quick-start-task-header__title', {
7888
'pfext-quick-start-task-header__title-success': taskStatus === QuickStartTaskStatus.SUCCESS,
7989
'pfext-quick-start-task-header__title-failed':
@@ -96,7 +106,7 @@ const QuickStartTaskHeader: React.FC<QuickStartTaskHeaderProps> = ({
96106
<div className="pfext-quick-start-task-header" ref={titleRef}>
97107
<TaskIcon taskIndex={taskIndex} taskStatus={taskStatus} />
98108
<Title headingLevel="h3" size={size} className={classNames}>
99-
<span dangerouslySetInnerHTML={{ __html: removeParagraphWrap(markdownConvert(title)) }} />
109+
<span dangerouslySetInnerHTML={{ __html: parsedTitle }} />
100110
{isActiveTask && subtitle && (
101111
<span
102112
className="pfext-quick-start-task-header__subtitle"

yarn.lock

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4771,7 +4771,7 @@ commander@^8.3.0:
47714771
resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66"
47724772
integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==
47734773

4774-
commander@^9.0.0, commander@^9.4.1:
4774+
commander@^9.4.1:
47754775
version "9.5.0"
47764776
resolved "https://registry.yarnpkg.com/commander/-/commander-9.5.0.tgz#bc08d1eb5cedf7ccb797a96199d41c7bc3e60d30"
47774777
integrity sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==
@@ -10823,6 +10823,11 @@ markdown-table@^2.0.0:
1082310823
dependencies:
1082410824
repeat-string "^1.0.0"
1082510825

10826+
marked@^15.0.6:
10827+
version "15.0.7"
10828+
resolved "https://registry.yarnpkg.com/marked/-/marked-15.0.7.tgz#f67d7e34d202ce087e6b879107b5efb04e743314"
10829+
integrity sha512-dgLIeKGLx5FwziAnsk4ONoGwHwGPJzselimvlVskE9XLN4Orv9u2VA3GWw/lYUqjfA0rUT/6fqKwfZJapP9BEg==
10830+
1082610831
marked@^4.0.16:
1082710832
version "4.3.0"
1082810833
resolved "https://registry.yarnpkg.com/marked/-/marked-4.3.0.tgz#796362821b019f734054582038b116481b456cf3"
@@ -14226,13 +14231,6 @@ shortid@^2.2.8:
1422614231
dependencies:
1422714232
nanoid "^2.1.0"
1422814233

14229-
14230-
version "2.1.0"
14231-
resolved "https://registry.yarnpkg.com/showdown/-/showdown-2.1.0.tgz#1251f5ed8f773f0c0c7bfc8e6fd23581f9e545c5"
14232-
integrity sha512-/6NVYu4U819R2pUIk79n67SYgJHWCce0a5xTP979WbNp0FL9MN1I1QK662IDU1b6JzKTvmhgI7T7JYIxBi3kMQ==
14233-
dependencies:
14234-
commander "^9.0.0"
14235-
1423614234
side-channel@^1.0.4:
1423714235
version "1.0.4"
1423814236
resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf"

0 commit comments

Comments
 (0)