@patternfly/quickstarts 6.2.0-prerelease.4 → 6.2.0-prerelease.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@patternfly/quickstarts",
3
- "version": "6.2.0-prerelease.4",
3
+ "version": "6.2.0-prerelease.5",
4
4
  "description": "PatternFly quick starts",
5
5
  "files": [
6
6
  "src",
@@ -48,7 +48,7 @@
48
48
  "@patternfly/react-core": "^6.0.0",
49
49
  "react": ">=18.0.0",
50
50
  "react-dom": ">=18.0.0",
51
- "showdown": ">=2.1.0"
51
+ "marked": "^15.0.6"
52
52
  },
53
53
  "dependencies": {
54
54
  "dompurify": "^3.1.3",
@@ -1,6 +1,6 @@
1
1
  import * as React from 'react';
2
2
  import { css } from '@patternfly/react-styles';
3
- import { Converter } from 'showdown';
3
+ import { marked } from 'marked';
4
4
  import { useForceRender } from '@console/shared';
5
5
  import { QuickStartContext, QuickStartContextValues } from '../../utils/quick-start-context';
6
6
 
@@ -15,18 +15,7 @@ interface ShowdownExtension {
15
15
  replace?: (...args: any[]) => string;
16
16
  }
17
17
 
18
- export const markdownConvert = (markdown, extensions?: ShowdownExtension[]) => {
19
- const converter = new Converter({
20
- tables: true,
21
- openLinksInNewWindow: true,
22
- strikethrough: true,
23
- emoji: false,
24
- });
25
-
26
- if (extensions) {
27
- converter.addExtension(extensions);
28
- }
29
-
18
+ export const markdownConvert = async (markdown: string, extensions?: ShowdownExtension[]) => {
30
19
  DOMPurify.addHook('beforeSanitizeElements', function (node) {
31
20
  // nodeType 1 = element type
32
21
 
@@ -82,12 +71,26 @@ export const markdownConvert = (markdown, extensions?: ShowdownExtension[]) => {
82
71
  }
83
72
  });
84
73
 
85
- return DOMPurify.sanitize(converter.makeHtml(markdown), {
86
- USE_PROFILES: {
87
- html: true,
88
- svg: true,
89
- },
90
- });
74
+ // Replace code fences with non markdown formatting relates tokens so that marked doesn't try to parse them as code spans
75
+ const markdownWithSubstitutedCodeFences = markdown.replace(/```/g, '@@@');
76
+ const parsedMarkdown = await marked.parse(markdownWithSubstitutedCodeFences);
77
+ // Swap the temporary tokens back to code fences before we run the extensions
78
+ let md = parsedMarkdown.replace(/@@@/g, '```');
79
+
80
+ if (extensions) {
81
+ // Convert code spans back to md format before we run the custom extension regexes
82
+ md = md.replace(/<code>(.*)<\/code>/g, '`$1`');
83
+
84
+ extensions.forEach(({ regex, replace }) => {
85
+ if (regex) {
86
+ md = md.replace(regex, replace);
87
+ }
88
+ });
89
+
90
+ // Convert any remaining backticks back into code spans
91
+ md = md.replace(/`(.*)`/g, '<code>$1</code>');
92
+ }
93
+ return DOMPurify.sanitize(md);
91
94
  };
92
95
 
93
96
  interface SyncMarkdownProps {
@@ -116,10 +119,18 @@ export const SyncMarkdownView: React.FC<SyncMarkdownProps> = ({
116
119
  className,
117
120
  }) => {
118
121
  const { getResource } = React.useContext<QuickStartContextValues>(QuickStartContext);
119
- const markup = React.useMemo(
120
- () => markdownConvert(content || emptyMsg || getResource('Not available'), extensions),
121
- [content, emptyMsg, extensions, getResource],
122
- );
122
+ const [markup, setMarkup] = React.useState<string>('');
123
+
124
+ React.useEffect(() => {
125
+ async function getMd() {
126
+ const md = await markdownConvert(
127
+ content || emptyMsg || getResource('Not available'),
128
+ extensions,
129
+ );
130
+ setMarkup(md);
131
+ }
132
+ getMd();
133
+ }, [content, emptyMsg, getResource, extensions]);
123
134
  const innerProps: InnerSyncMarkdownProps = {
124
135
  renderExtension: extensions?.length > 0 ? renderExtension : undefined,
125
136
  exactHeight,